From d038714421b225e9c7a69bca95244e051933117b Mon Sep 17 00:00:00 2001 From: Andreas Fernandez <a.fernandez@scripting-base.de> Date: Sat, 7 Jan 2017 20:14:37 +0100 Subject: [PATCH] [!!!][FEATURE] Allow reloading of backend topbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new API is introduced that allows to reload the backend’s topbar. The reload may be triggered via JavaScript and PHP. As the registered events of the toolbar items within the topbar get lost after reloading, the event registration for these toolbar items needs some adoption. The topbar is now reloaded in case of: - updating the user's avatar - after configuring an extension - opening the EXT:belog module from the System Information menu Resolves: #79196 Releases: master Change-Id: Ib6b65d7327c9db2b818ad9ad549cb2f2f00d1595 Reviewed-on: https://review.typo3.org/51183 Tested-by: TYPO3com <no-reply@typo3.com> Reviewed-by: Benni Mack <benni@typo3.org> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> Tested-by: Georg Ringer <georg.ringer@gmail.com> --- .../Classes/Controller/BackendController.php | 99 ++++++++++++------- .../Classes/Utility/BackendUtility.php | 7 ++ .../Configuration/Backend/AjaxRoutes.php | 4 + .../Private/Partials/Backend/Topbar.html | 37 +++++++ .../Private/Templates/Backend/Main.html | 40 +------- .../Resources/Public/JavaScript/LiveSearch.js | 9 +- .../JavaScript/Toolbar/ClearCacheMenu.js | 9 +- .../Public/JavaScript/Toolbar/ShortcutMenu.js | 7 +- .../Toolbar/SystemInformationMenu.js | 24 +++-- .../Resources/Public/JavaScript/Viewport.js | 15 +++ ...-79196-ToolbarItemEventHandlingChanged.rst | 45 +++++++++ .../Feature-79196-AllowReloadOfTopbar.rst | 51 ++++++++++ .../Classes/Controller/AbstractController.php | 3 + .../Classes/Controller/ActionController.php | 5 +- .../Controller/ConfigurationController.php | 13 ++- .../UploadExtensionFileController.php | 5 +- .../ViewHelpers/Be/TriggerViewHelper.php | 7 ++ .../Public/JavaScript/Toolbar/OpendocsMenu.js | 8 +- .../Controller/SetupModuleController.php | 2 + .../JavaScript/Toolbar/WorkspacesMenu.js | 4 +- 20 files changed, 298 insertions(+), 96 deletions(-) create mode 100644 typo3/sysext/backend/Resources/Private/Partials/Backend/Topbar.html create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Breaking-79196-ToolbarItemEventHandlingChanged.rst create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-79196-AllowReloadOfTopbar.rst diff --git a/typo3/sysext/backend/Classes/Controller/BackendController.php b/typo3/sysext/backend/Classes/Controller/BackendController.php index 5adbfed76341..fb5c0fcf87d8 100644 --- a/typo3/sysext/backend/Classes/Controller/BackendController.php +++ b/typo3/sysext/backend/Classes/Controller/BackendController.php @@ -75,6 +75,11 @@ class BackendController */ protected $templatePath = 'EXT:backend/Resources/Private/Templates/'; + /** + * @var string + */ + protected $partialPath = 'EXT:backend/Resources/Private/Partials/'; + /** * @var \TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository */ @@ -262,40 +267,8 @@ class BackendController // Prepare the scaffolding, at this point extension may still add javascript and css $view = $this->getFluidTemplateObject($this->templatePath . 'Backend/Main.html'); - // Extension Configuration to find the TYPO3 logo in the left corner - $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['backend'], ['allowed_classes' => false]); - $logoPath = ''; - if (!empty($extConf['backendLogo'])) { - $customBackendLogo = GeneralUtility::getFileAbsFileName($extConf['backendLogo']); - if (!empty($customBackendLogo)) { - $logoPath = $customBackendLogo; - } - } - // if no custom logo was set or the path is invalid, use the original one - if (empty($logoPath)) { - $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3_logo_orange.svg'); - $logoWidth = 22; - $logoHeight = 22; - } else { - // set width/height for custom logo - $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $logoPath); - $logoWidth = $imageInfo->getWidth() ?? '22'; - $logoHeight = $imageInfo->getHeight() ?? '22'; - - // High-resolution? - if (strpos($logoPath, '@2x.') !== false) { - $logoWidth /= 2; - $logoHeight /= 2; - } - } - - $view->assign('logoUrl', PathUtility::getAbsoluteWebPath($logoPath)); - $view->assign('logoWidth', $logoWidth); - $view->assign('logoHeight', $logoHeight); - $view->assign('applicationVersion', TYPO3_version); - $view->assign('siteName', $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']); $view->assign('moduleMenu', $this->generateModuleMenu()); - $view->assign('toolbar', $this->renderToolbar()); + $view->assign('topbar', $this->renderTopbar()); /****************************************************** * Now put the complete backend document together @@ -342,6 +315,52 @@ class BackendController $this->executeHook('renderPostProcess', $hookConfiguration); } + /** + * Renders the topbar, containing the backend logo, sitename etc. + * + * @return string + */ + protected function renderTopbar() + { + $view = $this->getFluidTemplateObject($this->partialPath . 'Backend/Topbar.html'); + + // Extension Configuration to find the TYPO3 logo in the left corner + $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['backend'], ['allowed_classes' => false]); + $logoPath = ''; + if (!empty($extConf['backendLogo'])) { + $customBackendLogo = GeneralUtility::getFileAbsFileName($extConf['backendLogo']); + if (!empty($customBackendLogo)) { + $logoPath = $customBackendLogo; + } + } + // if no custom logo was set or the path is invalid, use the original one + if (empty($logoPath)) { + $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3_logo_orange.svg'); + $logoWidth = 22; + $logoHeight = 22; + } else { + // set width/height for custom logo + $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $logoPath); + $logoWidth = $imageInfo->getWidth() ?? '22'; + $logoHeight = $imageInfo->getHeight() ?? '22'; + + // High-resolution? + if (strpos($logoPath, '@2x.') !== false) { + $logoWidth /= 2; + $logoHeight /= 2; + } + } + + $view->assign('logoUrl', PathUtility::getAbsoluteWebPath($logoPath)); + $view->assign('logoWidth', $logoWidth); + $view->assign('logoHeight', $logoHeight); + $view->assign('applicationVersion', TYPO3_version); + $view->assign('siteName', $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']); + $view->assign('toolbar', $this->renderToolbar()); + + return $view->render(); + } + /** * Loads the css and javascript files of all registered navigation widgets * @@ -836,6 +855,19 @@ class BackendController return $response; } + /** + * Returns the toolbar for the AJAX request + * + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return ResponseInterface + */ + public function getTopbar(ServerRequestInterface $request, ResponseInterface $response) + { + $response->getBody()->write(json_encode(['topbar' => $this->renderTopbar()])); + return $response; + } + /** * returns a new standalone view, shorthand function * @@ -845,6 +877,7 @@ class BackendController protected function getFluidTemplateObject($templatePathAndFileName = null) { $view = GeneralUtility::makeInstance(StandaloneView::class); + $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]); if ($templatePathAndFileName) { $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName)); } diff --git a/typo3/sysext/backend/Classes/Utility/BackendUtility.php b/typo3/sysext/backend/Classes/Utility/BackendUtility.php index f52e8b075b05..e7b4dc2d132d 100644 --- a/typo3/sysext/backend/Classes/Utility/BackendUtility.php +++ b/typo3/sysext/backend/Classes/Utility/BackendUtility.php @@ -3533,6 +3533,13 @@ class BackendUtility if (top && top.TYPO3.ModuleMenu && top.TYPO3.ModuleMenu.App) { top.TYPO3.ModuleMenu.App.refreshMenu(); }'; + break; + case 'updateTopbar': + $signals[] = ' + if (top && top.TYPO3.Backend && top.TYPO3.Backend.Topbar) { + top.TYPO3.Backend.Topbar.refresh(); + }'; + break; } } } diff --git a/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php b/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php index 2ee8bd2ff88b..b8a874752141 100644 --- a/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php +++ b/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php @@ -111,6 +111,10 @@ return [ 'path' => '/module-menu', 'target' => Controller\BackendController::class . '::getModuleMenu' ], + 'topbar' => [ + 'path' => '/topbar', + 'target' => Controller\BackendController::class . '::getTopbar' + ], // Log in into backend 'login' => [ diff --git a/typo3/sysext/backend/Resources/Private/Partials/Backend/Topbar.html b/typo3/sysext/backend/Resources/Private/Partials/Backend/Topbar.html new file mode 100644 index 000000000000..74ccfe209069 --- /dev/null +++ b/typo3/sysext/backend/Resources/Private/Partials/Backend/Topbar.html @@ -0,0 +1,37 @@ +{namespace core = TYPO3\CMS\Core\ViewHelpers} +<div class="scaffold-topbar t3js-scaffold-topbar"> + <div class="topbar"> + <div class="topbar-header t3js-topbar-header"> + <button class="topbar-button topbar-button-modulemenu t3js-topbar-button-modulemenu"> + <core:icon identifier="actions-move-move" alternativeMarkupIdentifier="inline" /> + </button> + <button class="topbar-button topbar-button-navigationcomponent t3js-topbar-button-navigationcomponent"> + <core:icon identifier="apps-pagetree-category-collapse-all" alternativeMarkupIdentifier="inline" /> + </button> + <div class="topbar-header-site"> + <a href="./" target="_top" title="{siteName} - {applicationVersion}"> + <span class="topbar-header-site-logo"> + <img src="{logoUrl}" width="{logoWidth}" height="{logoHeight}" title="TYPO3 Content Management System" alt="" /> + </span> + <span class="topbar-header-site-title"> + <span class="topbar-header-site-name">{siteName}</span> + <span class="topbar-header-site-version">{applicationVersion}</span> + </span> + </a> + </div> + <button class="topbar-button topbar-button-toolbar t3js-topbar-button-toolbar"> + <core:icon identifier="actions-system-extension-configure" alternativeMarkupIdentifier="inline" /> + </button> + <button class="topbar-button topbar-button-search t3js-topbar-button-search"> + <core:icon identifier="actions-search" alternativeMarkupIdentifier="inline" /> + </button> + </div> + </div> +</div> +<div class="scaffold-toolbar t3js-scaffold-toolbar"> + <div class="toolbar t3js-topbar-toolbar"> + <ul class="toolbar-list" data-typo3-role="typo3-module-menu"> + <f:format.raw>{toolbar}</f:format.raw> + </ul> + </div> +</div> \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Private/Templates/Backend/Main.html b/typo3/sysext/backend/Resources/Private/Templates/Backend/Main.html index 4e9132bdd84c..3f8f8d1bbc1a 100644 --- a/typo3/sysext/backend/Resources/Private/Templates/Backend/Main.html +++ b/typo3/sysext/backend/Resources/Private/Templates/Backend/Main.html @@ -1,48 +1,12 @@ -{namespace core = TYPO3\CMS\Core\ViewHelpers} <div class="scaffold t3js-scaffold scaffold-modulemenu-expanded"> - <div class="scaffold-topbar t3js-scaffold-topbar"> - - <div class="topbar"> - <div class="topbar-header t3js-topbar-header"> - <button class="topbar-button topbar-button-modulemenu t3js-topbar-button-modulemenu"> - <core:icon identifier="actions-move-move" alternativeMarkupIdentifier="inline" /> - </button> - <button class="topbar-button topbar-button-navigationcomponent t3js-topbar-button-navigationcomponent"> - <core:icon identifier="apps-pagetree-category-collapse-all" alternativeMarkupIdentifier="inline" /> - </button> - <div class="topbar-header-site"> - <a href="./" target="_top" title="{siteName} - {applicationVersion}"> - <span class="topbar-header-site-logo"> - <img src="{logoUrl}" width="{logoWidth}" height="{logoHeight}" title="TYPO3 Content Management System" alt="" /> - </span> - <span class="topbar-header-site-title"> - <span class="topbar-header-site-name">{siteName}</span> - <span class="topbar-header-site-version">{applicationVersion}</span> - </span> - </a> - </div> - <button class="topbar-button topbar-button-toolbar t3js-topbar-button-toolbar"> - <core:icon identifier="actions-system-extension-configure" alternativeMarkupIdentifier="inline" /> - </button> - <button class="topbar-button topbar-button-search t3js-topbar-button-search"> - <core:icon identifier="actions-search" alternativeMarkupIdentifier="inline" /> - </button> - </div> - </div> - + <div class="t3js-scaffold-header"> + <f:format.raw>{topbar}</f:format.raw> </div> <div class="scaffold-modulemenu t3js-scaffold-modulemenu"> <div class="modulemenu t3js-modulemenu"> <f:format.raw>{moduleMenu}</f:format.raw> </div> </div> - <div class="scaffold-toolbar t3js-scaffold-toolbar"> - <div class="toolbar t3js-topbar-toolbar"> - <ul class="toolbar-list" data-typo3-role="typo3-module-menu"> - <f:format.raw>{toolbar}</f:format.raw> - </ul> - </div> - </div> <div class="scaffold-content t3js-scaffold-content"> <div class="scaffold-content-navigation t3js-scaffold-content-navigation"> <div class="scaffold-content-navigation-component" data-component="typo3-navigationIframe"> diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/LiveSearch.js b/typo3/sysext/backend/Resources/Public/JavaScript/LiveSearch.js index 32d8cee916e3..9ef0d2b5140f 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/LiveSearch.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/LiveSearch.js @@ -16,7 +16,12 @@ * Global search to deal with everything in the backend that is search-related * @exports TYPO3/CMS/Backend/LiveSearch */ -define(['jquery', 'jquery/autocomplete', 'TYPO3/CMS/Backend/jquery.clearable'], function ($) { +define([ + 'jquery', + 'TYPO3/CMS/Backend/Viewport', + 'jquery/autocomplete', + 'TYPO3/CMS/Backend/jquery.clearable' +], function ($, Viewport) { 'use strict'; var containerSelector = '#typo3-cms-backend-backend-toolbaritems-livesearchtoolbaritem'; @@ -28,7 +33,7 @@ define(['jquery', 'jquery/autocomplete', 'TYPO3/CMS/Backend/jquery.clearable'], var url = TYPO3.settings.ajaxUrls['livesearch']; var category = ''; - $(function() { + Viewport.Topbar.Toolbar.registerEvent(function() { $(searchFieldSelector).autocomplete({ // ajax options serviceUrl: url, diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js index 22558fa61e5e..66041556d73f 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js @@ -16,7 +16,12 @@ * main functionality for clearing caches via the top bar * reloading the clear cache icon */ -define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Notification'], function($, Icons, Notification) { +define([ + 'jquery', + 'TYPO3/CMS/Backend/Icons', + 'TYPO3/CMS/Backend/Notification', + 'TYPO3/CMS/Backend/Viewport' +], function($, Icons, Notification, Viewport) { 'use strict'; /** @@ -76,7 +81,7 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Notification'], }); }; - $(ClearCacheMenu.initializeEvents); + Viewport.Topbar.Toolbar.registerEvent(ClearCacheMenu.initializeEvents); return ClearCacheMenu; }); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js index 91145a992219..a9da605d7ec4 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js @@ -19,8 +19,9 @@ define(['jquery', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Icons', - 'TYPO3/CMS/Backend/Notification' - ], function($, Modal, Icons, Notification) { + 'TYPO3/CMS/Backend/Notification', + 'TYPO3/CMS/Backend/Viewport' + ], function($, Modal, Icons, Notification, Viewport) { 'use strict'; /** @@ -210,7 +211,7 @@ define(['jquery', }); }; - $(ShortcutMenu.initializeEvents); + Viewport.Topbar.Toolbar.registerEvent(ShortcutMenu.initializeEvents); // expose as global object TYPO3.ShortcutMenu = ShortcutMenu; diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js index bf03794c4110..b3bb52e8d14b 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/SystemInformationMenu.js @@ -15,7 +15,12 @@ * Module: TYPO3/CMS/Backend/Toolbar/SystemInformationMenu * System information menu handler */ -define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Storage'], function($, Icons, Storage) { +define([ + 'jquery', + 'TYPO3/CMS/Backend/Icons', + 'TYPO3/CMS/Backend/Storage', + 'TYPO3/CMS/Backend/Viewport' +], function($, Icons, Storage, Viewport) { 'use strict'; /** @@ -28,10 +33,8 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Storage'], funct containerSelector: '#typo3-cms-backend-backend-toolbaritems-systeminformationtoolbaritem', toolbarIconSelector: '.toolbar-item-icon .t3js-icon', menuContainerSelector: '.dropdown-menu', - moduleLinks: '.t3js-systeminformation-module' - }, - elements: { - $counter: $('.t3js-systeminformation-counter') + moduleLinks: '.t3js-systeminformation-module', + counter: '.t3js-systeminformation-counter' } }; @@ -78,14 +81,15 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Storage'], funct */ SystemInformationMenu.updateCounter = function() { var $container = $(SystemInformationMenu.identifier.containerSelector).find(SystemInformationMenu.identifier.menuContainerSelector).find('.t3js-systeminformation-container'), + $counter = $(SystemInformationMenu.identifier.counter), count = $container.data('count'), badgeClass = $container.data('severityclass'); - SystemInformationMenu.elements.$counter.text(count).toggle(parseInt(count) > 0); - SystemInformationMenu.elements.$counter.removeClass(); + $counter.text(count).toggle(parseInt(count) > 0); + $counter.removeClass(); if (badgeClass !== '') { - SystemInformationMenu.elements.$counter.addClass('toolbar-item-badge badge ' + badgeClass); + $counter.addClass('toolbar-item-badge badge ' + badgeClass); } }; @@ -113,11 +117,11 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons', 'TYPO3/CMS/Backend/Storage'], funct $ajax.done(function() { // finally, open the module now TYPO3.ModuleMenu.App.showModule(requestedModule); - SystemInformationMenu.updateMenu(); + Viewport.Topbar.refresh(); }); }; - $(SystemInformationMenu.updateMenu); + Viewport.Topbar.Toolbar.registerEvent(SystemInformationMenu.updateMenu); return SystemInformationMenu; }); diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Viewport.js b/typo3/sysext/backend/Resources/Public/JavaScript/Viewport.js index 797f4653ae9c..75382df1f4b4 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/Viewport.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/Viewport.js @@ -142,6 +142,21 @@ define( return 0; } } + }, + Topbar: { + topbarSelector: '.t3js-scaffold-header', + refresh: function() { + $.ajax(TYPO3.settings.ajaxUrls['topbar']).done(function(data) { + $(TYPO3.Backend.Topbar.topbarSelector).html(data.topbar); + $(TYPO3.Backend.Topbar.topbarSelector).trigger('t3-topbar-update'); + }); + }, + Toolbar: { + registerEvent: function (callback) { + $(callback); + $(TYPO3.Backend.Topbar.topbarSelector).on('t3-topbar-update', callback); + } + } } }; diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-79196-ToolbarItemEventHandlingChanged.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-79196-ToolbarItemEventHandlingChanged.rst new file mode 100644 index 000000000000..96215609c757 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Breaking-79196-ToolbarItemEventHandlingChanged.rst @@ -0,0 +1,45 @@ +.. include:: ../../Includes.txt + +====================================================== +Breaking: #79196 - Toolbar item event handling changed +====================================================== + +See :issue:`79196` + +Description +=========== + +With the introduction of the topbar reloading mechanism, the event handling of toolbar items has changed. Reason is +that the event information gets lost, as the whole topbar is rendered from scratch after a reload. + + +Impact +====== + +After reloading the topbar, not migrated events will not get triggered anymore. + + +Affected Installations +====================== + +All installations with old-fashioned toolbar item registrations are affected. + + +Migration +========= + +In most cases it's sufficient to replace the register function with `Viewport.Topbar.Toolbar.registerEvent()`. + +Example: + +.. code-block:: javascript + + define(['jquery', 'TYPO3/CMS/Backend/Viewport'], function($, Viewport) { + // old registration + $(MyAwesomeItem.doStuff) + + // new registration + Viewport.Topbar.Toolbar.registerEvent(MyAwesomeItem.doStuff); + }); + +.. index:: Backend, JavaScript \ No newline at end of file diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-79196-AllowReloadOfTopbar.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-79196-AllowReloadOfTopbar.rst new file mode 100644 index 000000000000..dc8f5e70eabc --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-79196-AllowReloadOfTopbar.rst @@ -0,0 +1,51 @@ +.. include:: ../../Includes.txt + +======================================== +Feature: #79196 - Allow reload of topbar +======================================== + +See :issue:`79196` + +Description +=========== + +A new JavaScript API to reload the backend's topbar has been introduced to the TYPO3 Core. + + +Impact +====== + +The toolbar reloading may be triggered on JavaScript and PHP code level. To enforce the reloading on PHP side, +call :php:`\TYPO3\CMS\Backend\Utility\BackendUtility::setUpdateSignal('updateTopbar')`. + +Reloading the topbar via JavaScript requires the following code: + +.. code-block:: javascript + + // Either: RequireJS style + define(['TYPO3/CMS/Backend/Viewport'], function(Viewport) { + Viewport.Topbar.refresh(); + }); + + // Or: old-fashioned JavaScript + if (top && top.TYPO3.Backend && top.TYPO3.Backend.Topbar) { + top.TYPO3.Backend.Topbar.refresh(); + }'; + + +In case a toolbar item registers to the `load` event of the page, the registration must be changed. Reason is that the +event information gets lost, as the whole toolbar is rendered from scratch after a reload. + +Example: + +.. code-block:: javascript + + define(['jquery', 'TYPO3/CMS/Backend/Viewport'], function($, Viewport) { + // old registration + $(MyAwesomeItem.doStuff) + + // new registration + Viewport.Topbar.Toolbar.registerEvent(MyAwesomeItem.doStuff); + }); + +.. index:: Backend, JavaScript, PHP-API \ No newline at end of file diff --git a/typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php b/typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php index 2ff223e3bfdc..017ac8d9dcd3 100644 --- a/typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php +++ b/typo3/sysext/extensionmanager/Classes/Controller/AbstractController.php @@ -21,11 +21,14 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl { const TRIGGER_RefreshModuleMenu = 'refreshModuleMenu'; + const TRIGGER_RefreshTopbar = 'refreshTopbar'; + /** * @var array */ protected $triggerArguments = [ self::TRIGGER_RefreshModuleMenu, + self::TRIGGER_RefreshTopbar ]; /** diff --git a/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php b/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php index 97095620658b..fa16187010f7 100644 --- a/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php +++ b/typo3/sysext/extensionmanager/Classes/Controller/ActionController.php @@ -98,7 +98,10 @@ class ActionController extends AbstractController } catch (\TYPO3\CMS\Core\Package\Exception\PackageStatesFileNotWritableException $e) { $this->addFlashMessage($e->getMessage(), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR); } - $this->redirect('index', 'List', null, [self::TRIGGER_RefreshModuleMenu => true]); + $this->redirect('index', 'List', null, [ + self::TRIGGER_RefreshModuleMenu => true, + self::TRIGGER_RefreshTopbar => true + ]); } /** diff --git a/typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php b/typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php index cb511ea34e5c..9e6394874d67 100644 --- a/typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php +++ b/typo3/sysext/extensionmanager/Classes/Controller/ConfigurationController.php @@ -81,6 +81,8 @@ class ConfigurationController extends AbstractModuleController if (!isset($extension['key'])) { throw new ExtensionManagerException('Extension key not found.', 1359206803); } + $this->handleTriggerArguments(); + $extKey = $extension['key']; $configuration = $this->configurationItemRepository->findByExtensionKey($extKey); if ($configuration) { @@ -117,7 +119,12 @@ class ConfigurationController extends AbstractModuleController ) { $this->redirect('welcome', 'Distribution', null, ['extension' => $extension->getUid()]); } else { - $this->redirect('showConfigurationForm', null, null, ['extension' => ['key' => $extensionKey]]); + $this->redirect('showConfigurationForm', null, null, [ + 'extension' => [ + 'key' => $extensionKey + ], + self::TRIGGER_RefreshTopbar => true + ]); } } @@ -131,7 +138,9 @@ class ConfigurationController extends AbstractModuleController public function saveAndCloseAction(array $config, $extensionKey) { $this->saveConfiguration($config, $extensionKey); - $this->redirect('index', 'List'); + $this->redirect('index', 'List', null, [ + self::TRIGGER_RefreshTopbar => true + ]); } /** diff --git a/typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php b/typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php index 64fabba6ec43..cb53d8f584dc 100644 --- a/typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php +++ b/typo3/sysext/extensionmanager/Classes/Controller/UploadExtensionFileController.php @@ -179,7 +179,10 @@ class UploadExtensionFileController extends AbstractController $this->removeExtensionAndRestoreFromBackup($fileName); $this->addFlashMessage($exception->getMessage(), '', FlashMessage::ERROR); } - $this->redirect('index', 'List', null, [self::TRIGGER_RefreshModuleMenu => true]); + $this->redirect('index', 'List', null, [ + self::TRIGGER_RefreshModuleMenu => true, + self::TRIGGER_RefreshTopbar => true + ]); } /** diff --git a/typo3/sysext/extensionmanager/Classes/ViewHelpers/Be/TriggerViewHelper.php b/typo3/sysext/extensionmanager/Classes/ViewHelpers/Be/TriggerViewHelper.php index e09512bef413..11a2af7974ba 100644 --- a/typo3/sysext/extensionmanager/Classes/ViewHelpers/Be/TriggerViewHelper.php +++ b/typo3/sysext/extensionmanager/Classes/ViewHelpers/Be/TriggerViewHelper.php @@ -60,6 +60,13 @@ class TriggerViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Be\AbstractBackendV 'if (top && top.TYPO3.ModuleMenu.App) { top.TYPO3.ModuleMenu.App.refreshMenu(); }' ); } + + if (!empty($this->arguments['triggers'][AbstractController::TRIGGER_RefreshTopbar])) { + $pageRenderer->addJsInlineCode( + AbstractController::TRIGGER_RefreshTopbar, + 'if (top && top.TYPO3.Backend && top.TYPO3.Backend.Topbar) { top.TYPO3.Backend.Topbar.refresh(); }' + ); + } return ''; } } diff --git a/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js b/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js index da228a78fd42..a690a23bf46d 100644 --- a/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js +++ b/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js @@ -17,7 +17,11 @@ * - navigating to the documents * - updating the menu */ -define(['jquery', 'TYPO3/CMS/Backend/Icons'], function($, Icons) { +define([ + 'jquery', + 'TYPO3/CMS/Backend/Icons', + 'TYPO3/CMS/Backend/Viewport' +], function($, Icons, Viewport) { 'use strict'; /** @@ -113,7 +117,7 @@ define(['jquery', 'TYPO3/CMS/Backend/Icons'], function($, Icons) { $(OpendocsMenu.options.containerSelector).toggleClass('open'); }; - $(function() { + Viewport.Topbar.Toolbar.registerEvent(function() { OpendocsMenu.initializeEvents(); OpendocsMenu.updateMenu(); }); diff --git a/typo3/sysext/setup/Classes/Controller/SetupModuleController.php b/typo3/sysext/setup/Classes/Controller/SetupModuleController.php index 71d4d6c42328..fbf0d7c64718 100644 --- a/typo3/sysext/setup/Classes/Controller/SetupModuleController.php +++ b/typo3/sysext/setup/Classes/Controller/SetupModuleController.php @@ -299,6 +299,8 @@ class SetupModuleController extends AbstractModule } // Restore admin status after processing $beUser->user['admin'] = $isAdmin; + + BackendUtility::setUpdateSignal('updateTopbar'); } } } diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js index 2a57f0dc2440..c73d780a5946 100644 --- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js +++ b/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js @@ -16,7 +16,7 @@ * toolbar menu for the workspaces functionality to switch between the workspaces * and jump to the workspaces module */ -define(['jquery'], function($) { +define(['jquery', 'TYPO3/CMS/Backend/Viewport'], function($, Viewport) { 'use strict'; /** @@ -160,7 +160,7 @@ define(['jquery'], function($) { } }; - $(function() { + Viewport.Topbar.Toolbar.registerEvent(function() { WorkspacesMenu.initializeEvents(); WorkspacesMenu.updateBackendContext(); }); -- GitLab