From 4a36c82209079cf4b07e2256919f5b98acb7de0c Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Sat, 15 Nov 2014 13:55:22 +0100
Subject: [PATCH] [TASK] ToolbarItem interface improvements

Change new interface splitting item and drop down.
Refactor all toolbar items accordingly.
Styling changes will be done with second patch.

Change-Id: I6bfa87dbc85eb0312f4748283de788e27dda590e
Resolves: #62997
Releases: master
Reviewed-on: http://review.typo3.org/34205
Reviewed-by: Felix Kopp <felix-source@phorax.com>
Tested-by: Felix Kopp <felix-source@phorax.com>
Reviewed-by: Benjamin Mack <benni@typo3.org>
Tested-by: Benjamin Mack <benni@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../ToolbarItems/ClearCacheToolbarItem.php    | 138 +++++-----
 .../Backend/ToolbarItems/HelpToolbarItem.php  | 104 ++++----
 .../ToolbarItems/LiveSearchToolbarItem.php    |  66 +++--
 .../ToolbarItems/ShortcutToolbarItem.php      | 244 ++++++++++--------
 .../Backend/ToolbarItems/UserToolbarItem.php  | 149 ++++++-----
 .../Classes/Controller/BackendController.php  |  75 ++++--
 .../Classes/Toolbar/ToolbarItemInterface.php  |  41 ++-
 .../JavaScript/Toolbar/ClearCacheMenu.js      |   8 +-
 .../Public/JavaScript/Toolbar/ShortcutMenu.js |   2 +-
 typo3/sysext/backend/ext_localconf.php        |   2 +-
 .../sysext/core/Classes/Page/PageRenderer.php |   2 +-
 .../Configuration/DefaultConfiguration.php    |  10 +-
 .../ToolbarItems/OpendocsToolbarItem.php      | 159 +++++-------
 .../Public/JavaScript/Toolbar/OpendocsMenu.js |   2 +-
 .../ToolbarItems/ActionToolbarItem.php        | 145 ++++++-----
 .../Private/Styles/TYPO3/_topbar.less         |  28 +-
 .../Resources/Public/Css/visual/t3skin.css    |  18 +-
 .../WorkspaceSelectorToolbarItem.php          | 141 +++++-----
 .../JavaScript/Toolbar/WorkspacesMenu.js      |   2 +-
 19 files changed, 698 insertions(+), 638 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php
index bccb8a516c21..3d7218075f27 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ClearCacheToolbarItem.php
@@ -18,9 +18,10 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Toolbar\ClearCacheActionsHookInterface;
 
 /**
- * class to render the menu for the cache clearing actions
+ * Render cache clearing toolbar item
  *
  * @author Ingo Renner <ingo@typo3.org>
  */
@@ -29,43 +30,31 @@ class ClearCacheToolbarItem implements ToolbarItemInterface {
 	/**
 	 * @var array
 	 */
-	protected $cacheActions;
+	protected $cacheActions = array();
 
 	/**
 	 * @var array
 	 */
-	protected $optionValues;
-
-	/**
-	 * @var \TYPO3\CMS\Backend\Controller\BackendController
-	 */
-	protected $backendReference;
-
-	/**
-	 * TODO potentially unused
-	 * @var string
-	 */
-	public $backPath = '';
+	protected $optionValues = array();
 
 	/**
 	 * Constructor
 	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
 	 * @throws \UnexpectedValueException
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
-		$this->backendReference = $backendReference;
-		$this->cacheActions = array();
-		$this->optionValues = array();
+	public function __construct() {
 		$backendUser = $this->getBackendUser();
+		$languageService = $this->getLanguageService();
+
+		$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ClearCacheMenu');
 
 		// Clear all page-related caches
 		if ($backendUser->isAdmin() || $backendUser->getTSConfigVal('options.clearCache.pages')) {
 			$this->cacheActions[] = array(
 				'id' => 'pages',
-				'title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:flushPageCachesTitle', TRUE),
-				'description' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:flushPageCachesDescription', TRUE),
-				'href' => $this->backPath . 'tce_db.php?vC=' . $backendUser->veriCode() . '&cacheCmd=pages&ajaxCall=1' . BackendUtility::getUrlToken('tceAction'),
+				'title' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:flushPageCachesTitle', TRUE),
+				'description' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:flushPageCachesDescription', TRUE),
+				'href' => 'tce_db.php?vC=' . $backendUser->veriCode() . '&cacheCmd=pages&ajaxCall=1' . BackendUtility::getUrlToken('tceAction'),
 				'icon' => IconUtility::getSpriteIcon('actions-system-cache-clear-impact-low')
 			);
 			$this->optionValues[] = 'pages';
@@ -75,9 +64,9 @@ class ClearCacheToolbarItem implements ToolbarItemInterface {
 		if ($backendUser->isAdmin() || $backendUser->getTSConfigVal('options.clearCache.all')) {
 			$this->cacheActions[] = array(
 				'id' => 'all',
-				'title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:flushGeneralCachesTitle', TRUE),
-				'description' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:flushGeneralCachesDescription', TRUE),
-				'href' => $this->backPath . 'tce_db.php?vC=' . $backendUser->veriCode() . '&cacheCmd=all&ajaxCall=1' . BackendUtility::getUrlToken('tceAction'),
+				'title' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:flushGeneralCachesTitle', TRUE),
+				'description' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:flushGeneralCachesDescription', TRUE),
+				'href' => 'tce_db.php?vC=' . $backendUser->veriCode() . '&cacheCmd=all&ajaxCall=1' . BackendUtility::getUrlToken('tceAction'),
 				'icon' => IconUtility::getSpriteIcon('actions-system-cache-clear-impact-medium')
 			);
 			$this->optionValues[] = 'all';
@@ -91,18 +80,19 @@ class ClearCacheToolbarItem implements ToolbarItemInterface {
 			|| ((bool)$GLOBALS['TYPO3_CONF_VARS']['SYS']['clearCacheSystem'] === TRUE && $backendUser->isAdmin())) {
 			$this->cacheActions[] = array(
 				'id' => 'system',
-				'title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:flushSystemCachesTitle', TRUE),
-				'description' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:flushSystemCachesDescription', TRUE),
-				'href' => $this->backPath . 'tce_db.php?vC=' . $backendUser->veriCode() . '&cacheCmd=system&ajaxCall=1' . BackendUtility::getUrlToken('tceAction'),
+				'title' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:flushSystemCachesTitle', TRUE),
+				'description' => $languageService->sL('LLL:EXT:lang/locallang_core.xlf:flushSystemCachesDescription', TRUE),
+				'href' => 'tce_db.php?vC=' . $backendUser->veriCode() . '&cacheCmd=system&ajaxCall=1' . BackendUtility::getUrlToken('tceAction'),
 				'icon' => IconUtility::getSpriteIcon('actions-system-cache-clear-impact-high')
 			);
 			$this->optionValues[] = 'system';
 		}
+
 		// Hook for manipulating cacheActions
 		if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['additionalBackendItems']['cacheActions'])) {
 			foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['additionalBackendItems']['cacheActions'] as $cacheAction) {
 				$hookObject = GeneralUtility::getUserObj($cacheAction);
-				if (!$hookObject instanceof \TYPO3\CMS\Backend\Toolbar\ClearCacheActionsHookInterface) {
+				if (!$hookObject instanceof ClearCacheActionsHookInterface) {
 					throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Backend\\Toolbar\\ClearCacheActionsHookInterface', 1228262000);
 				}
 				$hookObject->manipulateCacheActions($this->cacheActions, $this->optionValues);
@@ -131,89 +121,89 @@ class ClearCacheToolbarItem implements ToolbarItemInterface {
 	}
 
 	/**
-	 * Creates the selector for workspaces
+	 * Render clear cache icon
 	 *
-	 * @return string Workspace selector as HTML select
+	 * @return string Icon HTML
 	 */
-	public function render() {
-		$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:rm.clearCache_clearCache', TRUE);
-		$this->addJavascriptToBackend();
-		$cacheMenu = array();
-		$cacheMenu[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . IconUtility::getSpriteIcon('apps-toolbar-menu-cache', array('title' => $title)) . '</a>';
-		$cacheMenu[] = '<ul class="dropdown-menu" role="menu">';
-		foreach ($this->cacheActions as $cacheAction) {
-			$cacheMenu[] = '<li><a href="' . htmlspecialchars($cacheAction['href'])
-				. '" title="' . htmlspecialchars($cacheAction['description'] ?: $cacheAction['title']) . '">'
-				. $cacheAction['icon'] . ' ' . htmlspecialchars($cacheAction['title']) . '</a></li>';
-		}
-		$cacheMenu[] = '</ul>';
-		return implode(LF, $cacheMenu);
+	public function getItem() {
+		$title = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.clearCache_clearCache', TRUE);
+		return IconUtility::getSpriteIcon('apps-toolbar-menu-cache', array('title' => $title));
 	}
 
 	/**
-	 * Adds the necessary JavaScript to the backend
+	 * Render drop down
 	 *
-	 * @return void
+	 * @return string Drop down HTML
 	 */
-	protected function addJavascriptToBackend() {
-		$this->backendReference->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ClearCacheMenu');
+	public function getDropDown() {
+		$result = array();
+		$result[] = '<ul>';
+		foreach ($this->cacheActions as $cacheAction) {
+			$title = $cacheAction['description'] ?: $cacheAction['title'];
+			$result[] = '<li>';
+			$result[] = '<a href="' . htmlspecialchars($cacheAction['href']) . '" title="' . htmlspecialchars($title) . '">';
+			$result[] = $cacheAction['icon'] . ' ' . htmlspecialchars($cacheAction['title']);
+			$result[] = '</a>';
+			$result[] = '</li>';
+		}
+		$result[] = '</ul>';
+		return implode(LF, $result);
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
+	 * No additional attributes needed.
 	 *
-	 * @return string List item HTML attibutes
+	 * @return array
 	 */
 	public function getAdditionalAttributes() {
-		return '';
+		return array();
 	}
 
 	/**
-	 * Return attribute id name
+	 * This item has a drop down
 	 *
-	 * @return string The name of the ID attribute
+	 * @return bool
 	 */
-	public function getIdAttribute() {
-		return 'clear-cache-actions-menu';
+	public function hasDropDown() {
+		return TRUE;
 	}
 
 	/**
-	 * Returns extra classes
+	 * Position relative to others
 	 *
-	 * @return array
+	 * @return int
 	 */
-	public function getExtraClasses() {
-		return array();
+	public function getIndex() {
+		return 25;
 	}
 
 	/**
-	 * This item has a drop down
+	 * Returns the current BE user.
 	 *
-	 * @return bool
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
 	 */
-	public function hasDropDown() {
-		return TRUE;
+	protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
 	}
 
 	/**
-	 * Returns the current BE user.
+	 * Returns current PageRenderer
 	 *
-	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+	 * @return \TYPO3\CMS\Core\Page\PageRenderer
 	 */
-	protected function getBackendUser() {
-		return $GLOBALS['BE_USER'];
+	protected function getPageRenderer() {
+		/** @var  \TYPO3\CMS\Backend\Template\DocumentTemplate $documentTemplate */
+		$documentTemplate = $GLOBALS['TBE_TEMPLATE'];
+		return $documentTemplate->getPageRenderer();
 	}
 
 	/**
-	 * Position relative to others
+	 * Returns LanguageService
 	 *
-	 * @return int
+	 * @return \TYPO3\CMS\Lang\LanguageService
 	 */
-	public function getIndex() {
-		return 25;
+	protected function getLanguageService() {
+		return $GLOBALS['LANG'];
 	}
 
 }
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/HelpToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/HelpToolbarItem.php
index 3f61b6a7dc98..0ff60fa42a5f 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/HelpToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/HelpToolbarItem.php
@@ -16,94 +16,86 @@ namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
+use TYPO3\CMS\Backend\Domain\Model\Module\BackendModule;
 
 /**
- * Help toobar item
+ * Help toolbar item
  */
 class HelpToolbarItem implements ToolbarItemInterface {
 
+	/**
+	 * @var \SplObjectStorage<BackendModule>
+	 */
+	protected $helpModuleMenu = NULL;
+
 	/**
 	 * Constructor
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
-	 * @throws \UnexpectedValueException
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
+	public function __construct() {
+		/** @var BackendModuleRepository $backendModuleRepository */
+		$backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
+		/** @var \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $userModuleMenu */
+		$helpModuleMenu = $backendModuleRepository->findByModuleName('help');
+		if ($helpModuleMenu && $helpModuleMenu->getChildren()->count() > 0) {
+			$this->helpModuleMenu = $helpModuleMenu;
+		}
 	}
 
 	/**
-	 * Checks whether the user has access to this toolbar item
+	 * Users see this if a module is available
 	 *
-	 * @return bool TRUE if user has access, FALSE if not
+	 * @return bool TRUE
 	 */
 	public function checkAccess() {
-		return TRUE;
+		$result = $this->helpModuleMenu ? TRUE : FALSE;
+		return $result;
 	}
 
 	/**
-	 * Creates the selector for workspaces
+	 * Render help icon
 	 *
 	 * @return string Help
 	 */
-	public function render() {
-		/** @var \TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository $backendModuleRepository */
-		$backendModuleRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository::class);
-		/** @var \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $userModuleMenu */
-		$helpModuleMenu = $backendModuleRepository->findByModuleName('help');
-
-		if ($helpModuleMenu === FALSE || $helpModuleMenu->getChildren()->count() < 1) {
-			return '';
-		}
+	public function getItem() {
+		return '<span class="fa fa-fw fa-question-circle"></span>';
+	}
 
+	/**
+	 * Render drop down
+	 *
+	 * @return string
+	 */
+	public function getDropDown() {
 		$dropdown = array();
-
-		$dropdown[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
-		$dropdown[] = '<span class="fa fa-fw fa-question-circle"></span>';
-		$dropdown[] = '</a>';
-
-		$dropdown[] = '<ul class="dropdown-menu">';
-		foreach ($helpModuleMenu->getChildren() as $module) {
+		$dropdown[] = '<ul>';
+		foreach ($this->helpModuleMenu->getChildren() as $module) {
+			/** @var BackendModule $module */
 			$moduleIcon = $module->getIcon();
-			$dropdown[] = '
-				<li id="' . $module->getName() . '" class="t3-menuitem-submodule submodule mod-' . $module->getName() . '" data-modulename="' . $module->getName() . '" data-navigationcomponentid="' . $module->getNavigationComponentId() . '" data-navigationframescript="' . $module->getNavigationFrameScript() . '" data-navigationframescriptparameters="' . $module->getNavigationFrameScriptParameters() . '">
-					<a title="' .$module->getDescription() . '" href="' . $module->getLink() . '" class="modlink">
-						<span class="submodule-icon">' . ($moduleIcon['html'] ?: $moduleIcon['html']) . '</span>
-						<span class="submodule-label">' . $module->getTitle() . '</span>
-					</a>
-				</li>';
+			$dropdown[] ='<li'
+				. ' id="' . $module->getName() . '"'
+				. ' class="t3-menuitem-submodule submodule mod-' . $module->getName() . '" '
+				. ' data-modulename="' . $module->getName() . '"'
+				. ' data-navigationcomponentid="' . $module->getNavigationComponentId() . '"'
+				. ' data-navigationframescript="' . $module->getNavigationFrameScript() . '"'
+				. ' data-navigationframescriptparameters="' . $module->getNavigationFrameScriptParameters() . '"'
+				. '>';
+			$dropdown[] = '<a title="' .$module->getDescription() . '" href="' . $module->getLink() . '" class="modlink">';
+			$dropdown[] = '<span class="submodule-icon">' . ($moduleIcon['html'] ?: $moduleIcon['html']) . '</span>';
+			$dropdown[] = '<span class="submodule-label">' . $module->getTitle() . '</span>';
+			$dropdown[] = '</a>';
+			$dropdown[] = '</li>';
 		}
 		$dropdown[] = '</ul>';
-
 		return implode(LF, $dropdown);
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
-	 *
-	 * @return string List item HTML attibutes
-	 */
-	public function getAdditionalAttributes() {
-		return '';
-	}
-
-	/**
-	 * Return attribute id name
-	 *
-	 * @return string The name of the ID attribute
-	 */
-	public function getIdAttribute() {
-		return 'topbar-help-menu';
-	}
-
-	/**
-	 * Returns extra classes
+	 * No additional attributes needed.
 	 *
 	 * @return array
 	 */
-	public function getExtraClasses() {
+	public function getAdditionalAttributes() {
 		return array();
 	}
 
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php
index 3f643334189c..8992a032cd7a 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/LiveSearchToolbarItem.php
@@ -15,6 +15,8 @@ namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
  */
 
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Module\ModuleLoader;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Adds backend live search to the toolbar
@@ -24,18 +26,11 @@ use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
  */
 class LiveSearchToolbarItem implements ToolbarItemInterface {
 
-	/**
-	 * @var \TYPO3\CMS\Backend\Controller\BackendController
-	 */
-	protected $backendReference;
-
 	/**
 	 * Constructor
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
-		$this->backendReference = $backendReference;
+	public function __construct() {
+		$this->getPageRenderer()->addJsFile('sysext/backend/Resources/Public/JavaScript/livesearch.js');
 	}
 
 	/**
@@ -46,7 +41,7 @@ class LiveSearchToolbarItem implements ToolbarItemInterface {
 	public function checkAccess() {
 		$access = FALSE;
 		// Loads the backend modules available for the logged in user.
-		$loadModules = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader::class);
+		$loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
 		$loadModules->observeWorkspaces = TRUE;
 		$loadModules->load($GLOBALS['TBE_MODULES']);
 		// Live search is heavily dependent on the list module and only available when that module is.
@@ -57,13 +52,11 @@ class LiveSearchToolbarItem implements ToolbarItemInterface {
 	}
 
 	/**
-	 * Creates the selector for workspaces
+	 * Render search field
 	 *
-	 * @return string Workspace selector as HTML select
+	 * @return string Live search form HTML
 	 */
-	public function render() {
-		$this->backendReference->addJavascriptFile('sysext/backend/Resources/Public/JavaScript/livesearch.js');
-
+	public function getItem() {
 		return '
 			<form class="navbar-form" role="search">
 				<div class="live-search-wrapper">
@@ -76,51 +69,50 @@ class LiveSearchToolbarItem implements ToolbarItemInterface {
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
+	 * This item needs to additional attributes
 	 *
-	 * @return string List item HTML attibutes
+	 * @return array
 	 */
 	public function getAdditionalAttributes() {
-		return '';
+		return array();
 	}
 
 	/**
-	 * Return attribute id name
+	 * This item has no drop down
 	 *
-	 * @return string The name of the ID attribute
+	 * @return bool
 	 */
-	public function getIdAttribute() {
-		return 'livesearch-menu';
+	public function hasDropDown() {
+		return FALSE;
 	}
 
 	/**
-	 * Returns extra classes
+	 * No drop down here
 	 *
-	 * @return array
+	 * @return string
 	 */
-	public function getExtraClasses() {
-		return array();
+	public function getDropDown() {
+		return '';
 	}
 
 	/**
-	 * This item has no drop down
+	 * Position relative to others, live search should be very right
 	 *
-	 * @return bool
+	 * @return int
 	 */
-	public function hasDropDown() {
-		return FALSE;
+	public function getIndex() {
+		return 90;
 	}
 
 	/**
-	 * Position relative to others, live search should be very right
+	 * Returns current PageRenderer
 	 *
-	 * @return int
+	 * @return \TYPO3\CMS\Core\Page\PageRenderer
 	 */
-	public function getIndex() {
-		return 90;
+	protected function getPageRenderer() {
+		/** @var  \TYPO3\CMS\Backend\Template\DocumentTemplate $documentTemplate */
+		$documentTemplate = $GLOBALS['TBE_TEMPLATE'];
+		return $documentTemplate->getPageRenderer();
 	}
 
 }
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
index cba754290866..93ceab635c6b 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
@@ -19,6 +19,7 @@ use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Module\ModuleLoader;
 
 /**
  * Class to render the shortcut menu
@@ -27,17 +28,15 @@ use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
  */
 class ShortcutToolbarItem implements ToolbarItemInterface {
 
-	const SUPERGLOBAL_GROUP = -100;
-
 	/**
-	 * @var string
+	 * @const integer Number of super global group
 	 */
-	public $perms_clause;
+	const SUPERGLOBAL_GROUP = -100;
 
 	/**
 	 * @var string
 	 */
-	public $backPath;
+	public $perms_clause;
 
 	/**
 	 * @var array
@@ -64,27 +63,17 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 */
 	protected $groupLabels;
 
-	/**
-	 * Reference back to the backend object
-	 *
-	 * @var \TYPO3\CMS\Backend\Controller\BackendController
-	 */
-	protected $backendReference;
-
 	/**
 	 * Constructor
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
+	public function __construct() {
 		if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
-			$GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_misc.xlf');
+			$this->getLanguageService()->includeLLFile('EXT:lang/locallang_misc.xlf');
 			// Needed to get the correct icons when reloading the menu after saving it
-			$loadModules = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Module\ModuleLoader::class);
+			$loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
 			$loadModules->load($GLOBALS['TBE_MODULES']);
 		}
-		$this->backendReference = $backendReference;
-		$this->shortcuts = array();
+
 		// By default, 5 groups are set
 		$this->shortcutGroups = array(
 			1 => '1',
@@ -95,6 +84,8 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 		);
 		$this->shortcutGroups = $this->initShortcutGroups();
 		$this->shortcuts = $this->initShortcuts();
+
+		$this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ShortcutMenu');
 	}
 
 	/**
@@ -103,38 +94,37 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @return bool TRUE if user has access, FALSE if not
 	 */
 	public function checkAccess() {
-		return (bool)$GLOBALS['BE_USER']->getTSConfigVal('options.enableBookmarks');
+		return (bool)$this->getBackendUser()->getTSConfigVal('options.enableBookmarks');
 	}
 
 	/**
-	 * Creates the shortcut menu (default renderer)
+	 * Render shortcut icon
 	 *
-	 * @return string Workspace selector as HTML select
-	 */
-	public function render() {
-		$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarks', TRUE);
-		$this->backendReference->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Toolbar/ShortcutMenu');
-		$shortcutMenu = array();
-		$shortcutMenu[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . IconUtility::getSpriteIcon('apps-toolbar-menu-shortcut', array('title' => $title)) . '</a>';
-		$shortcutMenu[] = '<div class="dropdown-menu" role="menu">';
-		$shortcutMenu[] = $this->renderMenu();
-		$shortcutMenu[] = '</div>';
-		return implode(LF, $shortcutMenu);
+	 * @return string HTML
+	 */
+	public function getItem() {
+		return IconUtility::getSpriteIcon(
+			'apps-toolbar-menu-shortcut',
+			array(
+				'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarks', TRUE),
+			)
+		);
 	}
 
 	/**
-	 * Renders the pure contents of the menu
+	 * Render drop down content
 	 *
-	 * @return string The menu's content
-	 */
-	public function renderMenu() {
-		$shortcutGroup = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksGroup', TRUE);
-		$shortcutEdit = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksEdit', TRUE);
-		$shortcutDelete = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksDelete', TRUE);
-		$groupIcon = '<img' . IconUtility::skinImg($this->backPath, 'gfx/i/sysf.gif', 'width="18" height="16"') . ' title="' . $shortcutGroup . '" alt="' . $shortcutGroup . '" />';
-		$editIcon = '<img' . IconUtility::skinImg($this->backPath, 'gfx/edit2.gif', 'width="11" height="12"') . ' title="' . $shortcutEdit . '" alt="' . $shortcutEdit . '"';
-		$deleteIcon = '<img' . IconUtility::skinImg($this->backPath, 'gfx/garbage.gif', 'width="11" height="12"') . ' title="' . $shortcutDelete . '" alt="' . $shortcutDelete . '" />';
-		$shortcutMenu[] = '<table border="0" cellspacing="0" cellpadding="0" class="shortcut-list">';
+	 * @return string HTML
+	 */
+	public function getDropDown() {
+		$languageService = $this->getLanguageService();
+		$shortcutGroup = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksGroup', TRUE);
+		$shortcutEdit = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksEdit', TRUE);
+		$shortcutDelete = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarksDelete', TRUE);
+		$groupIcon = '<img' . IconUtility::skinImg('', 'gfx/i/sysf.gif', 'width="18" height="16"') . ' title="' . $shortcutGroup . '" alt="' . $shortcutGroup . '" />';
+		$editIcon = '<img' . IconUtility::skinImg('', 'gfx/edit2.gif', 'width="11" height="12"') . ' title="' . $shortcutEdit . '" alt="' . $shortcutEdit . '"';
+		$deleteIcon = '<img' . IconUtility::skinImg('', 'gfx/garbage.gif', 'width="11" height="12"') . ' title="' . $shortcutDelete . '" alt="' . $shortcutDelete . '" />';
+		$shortcutMenu[] = '<table border="0" class="shortcut-list">';
 		// Render shortcuts with no group (group id = 0) first
 		$noGroupShortcuts = $this->getShortcutsByGroup(0);
 		foreach ($noGroupShortcuts as $shortcut) {
@@ -182,11 +172,11 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 		}
 		if (count($shortcutMenu) == 1) {
 			// No shortcuts added yet, show a small help message how to add shortcuts
-			$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarks', TRUE);
+			$title = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.bookmarks', TRUE);
 			$icon = IconUtility::getSpriteIcon('actions-system-shortcut-new', array(
 				'title' => $title
 			));
-			$label = str_replace('%icon%', $icon, $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xlf:bookmarkDescription'));
+			$label = str_replace('%icon%', $icon, $languageService->sL('LLL:EXT:lang/locallang_misc.xlf:bookmarkDescription'));
 			$shortcutMenu[] = '<tr><td style="padding:1px 2px; color: #838383;">' . $label . '</td></tr>';
 		}
 		$shortcutMenu[] = '</table>';
@@ -201,38 +191,17 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
 	 * @return void
 	 */
-	public function renderAjaxMenu($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj = NULL) {
-		$menuContent = $this->renderMenu();
+	public function renderAjaxMenu($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj = NULL) {
+		$menuContent = $this->getDropDown();
 		$ajaxObj->addContent('shortcutMenu', $menuContent);
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
-	 *
-	 * @return string List item HTML attibutes
-	 */
-	public function getAdditionalAttributes() {
-		return '';
-	}
-
-	/**
-	 * Return attribute id name
-	 *
-	 * @return string The name of the ID attribute
-	 */
-	public function getIdAttribute() {
-		return 'shortcut-menu';
-	}
-
-	/**
-	 * Returns extra classes
+	 * This toolbar item needs no additional attributes
 	 *
 	 * @return array
 	 */
-	public function getExtraClasses() {
+	public function getAdditionalAttributes() {
 		return array();
 	}
 
@@ -251,18 +220,20 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @return array Array of shortcuts
 	 */
 	protected function initShortcuts() {
+		$databaseConnection = $this->getDatabaseConnection();
 		$globalGroupIdList = implode(',', array_keys($this->getGlobalShortcutGroups()));
-		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+		$backendUser = $this->getBackendUser();
+		$res = $databaseConnection->exec_SELECTquery(
 			'*',
 			'sys_be_shortcuts',
-			'(userid = ' . (int)$GLOBALS['BE_USER']->user['uid'] . ' AND sc_group>=0) OR sc_group IN (' . $globalGroupIdList . ')',
+			'(userid = ' . (int)$backendUser->user['uid'] . ' AND sc_group>=0) OR sc_group IN (' . $globalGroupIdList . ')',
 			'',
 			'sc_group,sorting'
 		);
 		// Traverse shortcuts
 		$lastGroup = 0;
 		$shortcuts = array();
-		while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+		while ($row = $databaseConnection->sql_fetch_assoc($res)) {
 			$shortcut = array('raw' => $row);
 
 			list($row['module_name'], $row['M_module_name']) = explode('|', $row['module_name']);
@@ -286,20 +257,20 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 			// Check for module access
 			$moduleName = $row['M_module_name'] ?: $row['module_name'];
 			$pageId = $this->getLinkedPageId($row['url']);
-			if (!$GLOBALS['BE_USER']->isAdmin()) {
-				if (!isset($GLOBALS['LANG']->moduleLabels['tabs_images'][$moduleName . '_tab'])) {
+			if (!$backendUser->isAdmin()) {
+				if (!isset($this->getLanguageService()->moduleLabels['tabs_images'][$moduleName . '_tab'])) {
 					// Nice hack to check if the user has access to this module
 					// - otherwise the translation label would not have been loaded :-)
 					continue;
 				}
 				if (MathUtility::canBeInterpretedAsInteger($pageId)) {
 					// Check for webmount access
-					if (!$GLOBALS['BE_USER']->isInWebMount($pageId)) {
+					if (!$backendUser->isInWebMount($pageId)) {
 						continue;
 					}
 					// Check for record access
 					$pageRow = BackendUtility::getRecord('pages', $pageId);
-					if (!$GLOBALS['BE_USER']->doesUserHaveAccess($pageRow, ($perms = 1))) {
+					if (!$backendUser->doesUserHaveAccess($pageRow, ($perms = 1))) {
 						continue;
 					}
 				}
@@ -394,13 +365,15 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @return array
 	 */
 	protected function initShortcutGroups() {
+		$languageService = $this->getLanguageService();
+		$backendUser = $this->getBackendUser();
 		// Groups from TSConfig
-		$bookmarkGroups = $GLOBALS['BE_USER']->getTSConfigProp('options.bookmarkGroups');
+		$bookmarkGroups = $backendUser->getTSConfigProp('options.bookmarkGroups');
 		if (is_array($bookmarkGroups) && count($bookmarkGroups)) {
 			foreach ($bookmarkGroups as $groupId => $label) {
 				if (!empty($label)) {
 					$this->shortcutGroups[$groupId] = (string)$label;
-				} elseif ($GLOBALS['BE_USER']->isAdmin()) {
+				} elseif ($backendUser->isAdmin()) {
 					unset($this->shortcutGroups[$groupId]);
 				}
 			}
@@ -419,17 +392,17 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 			$groupId = (int)$groupId;
 			$label = $groupLabel;
 			if ($groupLabel == '1') {
-				$label = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xlf:bookmark_group_' . abs($groupId), TRUE);
+				$label = $languageService->sL('LLL:EXT:lang/locallang_misc.xlf:bookmark_group_' . abs($groupId), TRUE);
 				if (empty($label)) {
 					// Fallback label
-					$label = $GLOBALS['LANG']->getLL('bookmark_group', 1) . ' ' . abs($groupId);
+					$label = $languageService->getLL('bookmark_group', 1) . ' ' . abs($groupId);
 				}
 			}
 			if ($groupId < 0) {
 				// Global group
-				$label = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xlf:bookmark_global', TRUE) . ': ' . (!empty($label) ? $label : abs($groupId));
+				$label = $languageService->sL('LLL:EXT:lang/locallang_misc.xlf:bookmark_global', TRUE) . ': ' . (!empty($label) ? $label : abs($groupId));
 				if ($groupId === self::SUPERGLOBAL_GROUP) {
-					$label = $GLOBALS['LANG']->getLL('bookmark_global', 1) . ': ' . $GLOBALS['LANG']->getLL('bookmark_all', 1);
+					$label = $languageService->getLL('bookmark_global', 1) . ': ' . $languageService->getLL('bookmark_all', 1);
 				}
 			}
 			$this->shortcutGroups[$groupId] = $label;
@@ -444,13 +417,13 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
 	 * @return void
 	 */
-	public function getAjaxShortcutEditForm($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj = NULL) {
+	public function getAjaxShortcutEditForm($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj = NULL) {
 		$selectedShortcutId = (int)GeneralUtility::_GP('shortcutId');
 		$selectedShortcutGroupId = (int)GeneralUtility::_GP('shortcutGroup');
 		$selectedShortcut = $this->getShortcutById($selectedShortcutId);
 
 		$shortcutGroups = $this->shortcutGroups;
-		if (!$GLOBALS['BE_USER']->isAdmin()) {
+		if (!$this->getBackendUser()->isAdmin()) {
 			foreach ($shortcutGroups as $groupId => $groupName) {
 				if ((int)$groupId < 0) {
 					unset($shortcutGroups[$groupId]);
@@ -478,13 +451,14 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
 	 * @return void
 	 */
-	public function deleteAjaxShortcut($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj = NULL) {
+	public function deleteAjaxShortcut($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj = NULL) {
+		$databaseConnection = $this->getDatabaseConnection();
 		$shortcutId = (int)GeneralUtility::_POST('shortcutId');
 		$fullShortcut = $this->getShortcutById($shortcutId);
 		$ajaxReturn = 'failed';
-		if ($fullShortcut['raw']['userid'] == $GLOBALS['BE_USER']->user['uid']) {
-			$GLOBALS['TYPO3_DB']->exec_DELETEquery('sys_be_shortcuts', 'uid = ' . $shortcutId);
-			if ($GLOBALS['TYPO3_DB']->sql_affected_rows() == 1) {
+		if ($fullShortcut['raw']['userid'] == $this->getBackendUser()->user['uid']) {
+			$databaseConnection->exec_DELETEquery('sys_be_shortcuts', 'uid = ' . $shortcutId);
+			if ($databaseConnection->sql_affected_rows() == 1) {
 				$ajaxReturn = 'deleted';
 			}
 		}
@@ -498,7 +472,9 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Oject of type AjaxRequestHandler
 	 * @return void
 	 */
-	public function createAjaxShortcut($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj = NULL) {
+	public function createAjaxShortcut($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj = NULL) {
+		$databaseConnection = $this->getDatabaseConnection();
+		$languageService = $this->getLanguageService();
 		$shortcutCreated = 'failed';
 		// Default name
 		$shortcutName = 'Shortcut';
@@ -517,10 +493,10 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 				$shortcut['recordid'] = key($queryParameters['edit'][$shortcut['table']]);
 				if ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] == 'edit') {
 					$shortcut['type'] = 'edit';
-					$shortcutNamePrepend = $GLOBALS['LANG']->getLL('shortcut_edit', 1);
+					$shortcutNamePrepend = $languageService->getLL('shortcut_edit', 1);
 				} elseif ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] == 'new') {
 					$shortcut['type'] = 'new';
-					$shortcutNamePrepend = $GLOBALS['LANG']->getLL('shortcut_create', 1);
+					$shortcutNamePrepend = $languageService->getLL('shortcut_create', 1);
 				}
 			} else {
 				$shortcut['type'] = 'other';
@@ -534,7 +510,7 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 					if ($shortcut['type'] == 'other') {
 						$shortcutName = $page['title'];
 					} else {
-						$shortcutName = $shortcutNamePrepend . ' ' . $GLOBALS['LANG']->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']) . ' (' . $page['title'] . ')';
+						$shortcutName = $shortcutNamePrepend . ' ' . $languageService->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']) . ' (' . $page['title'] . ')';
 					}
 				}
 			} else {
@@ -549,14 +525,14 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 			// adding the shortcut
 			if ($module && $url) {
 				$fieldValues = array(
-					'userid' => $GLOBALS['BE_USER']->user['uid'],
+					'userid' => $this->getBackendUser()->user['uid'],
 					'module_name' => $module . '|' . $motherModule,
 					'url' => $url,
 					'description' => $shortcutName,
 					'sorting' => $GLOBALS['EXEC_TIME']
 				);
-				$GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_be_shortcuts', $fieldValues);
-				if ($GLOBALS['TYPO3_DB']->sql_affected_rows() == 1) {
+				$databaseConnection->exec_INSERTquery('sys_be_shortcuts', $fieldValues);
+				if ($databaseConnection->sql_affected_rows() == 1) {
 					$shortcutCreated = 'success';
 				}
 			}
@@ -572,22 +548,24 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
 	 * @return void
 	 */
-	public function setAjaxShortcut($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj = NULL) {
+	public function setAjaxShortcut($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj = NULL) {
+		$databaseConnection = $this->getDatabaseConnection();
+		$backendUser = $this->getBackendUser();
 		$shortcutId = (int)GeneralUtility::_POST('shortcutId');
 		$shortcutName = strip_tags(GeneralUtility::_POST('shortcutTitle'));
 		$shortcutGroupId = (int)GeneralUtility::_POST('shortcutGroup');
-		if ($shortcutGroupId > 0 || $GLOBALS['BE_USER']->isAdmin()) {
+		if ($shortcutGroupId > 0 || $backendUser->isAdmin()) {
 			// Users can delete only their own shortcuts (except admins)
-			$addUserWhere = !$GLOBALS['BE_USER']->isAdmin() ? ' AND userid=' . (int)$GLOBALS['BE_USER']->user['uid'] : '';
+			$addUserWhere = !$backendUser->isAdmin() ? ' AND userid=' . (int)$backendUser->user['uid'] : '';
 			$fieldValues = array(
 				'description' => $shortcutName,
 				'sc_group' => $shortcutGroupId
 			);
-			if ($fieldValues['sc_group'] < 0 && !$GLOBALS['BE_USER']->isAdmin()) {
+			if ($fieldValues['sc_group'] < 0 && !$backendUser->isAdmin()) {
 				$fieldValues['sc_group'] = 0;
 			}
-			$GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_be_shortcuts', 'uid=' . $shortcutId . $addUserWhere, $fieldValues);
-			$affectedRows = $GLOBALS['TYPO3_DB']->sql_affected_rows();
+			$databaseConnection->exec_UPDATEquery('sys_be_shortcuts', 'uid=' . $shortcutId . $addUserWhere, $fieldValues);
+			$affectedRows = $databaseConnection->sql_affected_rows();
 			if ($affectedRows == 1) {
 				$ajaxObj->addContent('shortcut', $shortcutName);
 			} else {
@@ -643,6 +621,8 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @return string Shortcut icon as img tag
 	 */
 	protected function getShortcutIcon($row, $shortcut) {
+		$databaseConnection = $this->getDatabaseConnection();
+		$languageService = $this->getLanguageService();
 		switch ($row['module_name']) {
 			case 'xMOD_alt_doc.php':
 				$table = $shortcut['table'];
@@ -678,13 +658,13 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 						'FROM' => $table,
 						'WHERE' => 'uid IN (' . $recordid . ') ' . $permissionClause . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table)
 					);
-					$result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($sqlQueryParts);
-					$row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result);
-					$icon = IconUtility::getIcon($table, $row, $this->backPath);
+					$result = $databaseConnection->exec_SELECT_queryArray($sqlQueryParts);
+					$row = $databaseConnection->sql_fetch_assoc($result);
+					$icon = IconUtility::getIcon($table, $row);
 				} elseif ($shortcut['type'] == 'new') {
-					$icon = IconUtility::getIcon($table, array(), $this->backPath);
+					$icon = IconUtility::getIcon($table, array());
 				}
-				$icon = IconUtility::skinImg($this->backPath, $icon, '', 1);
+				$icon = IconUtility::skinImg('', $icon, '', 1);
 				break;
 			case 'file_edit':
 				$icon = 'gfx/edit_file.gif';
@@ -693,8 +673,8 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 				$icon = 'gfx/edit_rtewiz.gif';
 				break;
 			default:
-				if ($GLOBALS['LANG']->moduleLabels['tabs_images'][$row['module_name'] . '_tab']) {
-					$icon = $GLOBALS['LANG']->moduleLabels['tabs_images'][$row['module_name'] . '_tab'];
+				if ($languageService->moduleLabels['tabs_images'][$row['module_name'] . '_tab']) {
+					$icon = $languageService->moduleLabels['tabs_images'][$row['module_name'] . '_tab'];
 					// Change icon of fileadmin references - otherwise it doesn't differ with Web->List
 					$icon = str_replace('mod/file/list/list.gif', 'mod/file/file.gif', $icon);
 					if (GeneralUtility::isAbsPath($icon)) {
@@ -704,7 +684,7 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 					$icon = 'gfx/dummy_module.gif';
 				}
 		}
-		return '<img src="' . $icon . '" alt="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.shortcut', TRUE) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.shortcut', TRUE) . '" />';
+		return '<img src="' . $icon . '" alt="' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.shortcut', TRUE) . '" title="' . $languageService->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.shortcut', TRUE) . '" />';
 	}
 
 	/**
@@ -716,14 +696,14 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 	 * @return string Title for the shortcut icon
 	 */
 	protected function getShortcutIconTitle($shortcutLabel, $moduleName, $parentModuleName = '') {
-		$title = '';
+		$languageService = $this->getLanguageService();
 		if (substr($moduleName, 0, 5) == 'xMOD_') {
 			$title = substr($moduleName, 5);
 		} else {
 			$splitModuleName = explode('_', $moduleName);
-			$title = $GLOBALS['LANG']->moduleLabels['tabs'][$splitModuleName[0] . '_tab'];
+			$title = $languageService->moduleLabels['tabs'][$splitModuleName[0] . '_tab'];
 			if (count($splitModuleName) > 1) {
-				$title .= '>' . $GLOBALS['LANG']->moduleLabels['tabs'][($moduleName . '_tab')];
+				$title .= '>' . $languageService->moduleLabels['tabs'][($moduleName . '_tab')];
 			}
 		}
 		if ($parentModuleName) {
@@ -752,4 +732,42 @@ class ShortcutToolbarItem implements ToolbarItemInterface {
 		return 20;
 	}
 
+	/**
+	 * Returns the current BE user.
+	 *
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+	 */
+	protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
+	}
+
+	/**
+	 * Returns current PageRenderer
+	 *
+	 * @return \TYPO3\CMS\Core\Page\PageRenderer
+	 */
+	protected function getPageRenderer() {
+		/** @var  \TYPO3\CMS\Backend\Template\DocumentTemplate $documentTemplate */
+		$documentTemplate = $GLOBALS['TBE_TEMPLATE'];
+		return $documentTemplate->getPageRenderer();
+	}
+
+	/**
+	 * Returns LanguageService
+	 *
+	 * @return \TYPO3\CMS\Lang\LanguageService
+	 */
+	protected function getLanguageService() {
+		return $GLOBALS['LANG'];
+	}
+
+	/**
+	 * Return DatabaseConnection
+	 *
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+	 */
+	protected function getDatabaseConnection() {
+		return $GLOBALS['TYPO3_DB'];
+	}
+
 }
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
index b62182dbd715..baf091c68709 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/UserToolbarItem.php
@@ -16,132 +16,151 @@ namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Utility\IconUtility;
+use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
+use TYPO3\CMS\Backend\Domain\Model\Module\BackendModule;
 
 /**
- * User toobar item
+ * User toolbar item
  */
 class UserToolbarItem implements ToolbarItemInterface {
 
 	/**
-	 * Constructor
+	 * Item is always enabled
 	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
-	 * @throws \UnexpectedValueException
-	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
-	}
-
-	/**
-	 * Checks whether the user has access to this toolbar item
-	 *
-	 * @return bool TRUE if user has access, FALSE if not
+	 * @return bool TRUE
 	 */
 	public function checkAccess() {
 		return TRUE;
 	}
 
 	/**
-	 * Creates the selector for workspaces
+	 * Render username
 	 *
-	 * @return string Workspace selector as HTML select
+	 * @return string HTML
 	 */
-	public function render() {
-		$icon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-user-' . ($GLOBALS['BE_USER']->isAdmin() ? 'admin' : 'backend'));
+	public function getItem() {
+		$backendUser = $this->getBackendUser();
+		$languageService = $this->getLanguageService();
+		$icon = IconUtility::getSpriteIcon('status-user-' . ($backendUser->isAdmin() ? 'admin' : 'backend'));
 
-		$realName = $GLOBALS['BE_USER']->user['realName'];
-		$username = $GLOBALS['BE_USER']->user['username'];
+		$realName = $backendUser->user['realName'];
+		$username = $backendUser->user['username'];
 		$label = $realName ?: $username;
 		$title = $username;
 
-		// Superuser mode
-		if ($GLOBALS['BE_USER']->user['ses_backuserid']) {
-			$title = $GLOBALS['LANG']->getLL('switchtouser') . ': ' . $username;
-			$label = $GLOBALS['LANG']->getLL('switchtousershort') . ' ' . ($realName ? $realName . ' (' . $username . ')' : $username);
+		// Switch user mode
+		if ($backendUser->user['ses_backuserid']) {
+			$title = $languageService->getLL('switchtouser') . ': ' . $username;
+			$label = $languageService->getLL('switchtousershort') . ' ' . ($realName ? $realName . ' (' . $username . ')' : $username);
 		}
 
-
 		$html = array();
-		$html[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
-		$html[] = $icon . '<span title="' . htmlspecialchars($title) . '">' . htmlspecialchars($label) . ' <span class="caret"></span></span>';
-		$html[] = '</a>';
+		$html[] = $icon;
+		$html[] = '<span title="' . htmlspecialchars($title) . '">';
+		$html[] = htmlspecialchars($label);
+		$html[] = '<span class="caret"></span></span>';
 
-		$html[] = '<ul class="dropdown-menu" role="menu">';
+		return implode(LF, $html);
+	}
 
-		/** @var \TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository $backendModuleRepository */
-		$backendModuleRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository::class);
+	/**
+	 * Render drop down
+	 *
+	 * @return string HTML
+	 */
+	public function getDropDown() {
+		$backendUser = $this->getBackendUser();
+		$languageService = $this->getLanguageService();
+
+		$dropdown = array();
+		$dropdown[] = '<ul>';
+
+		/** @var BackendModuleRepository $backendModuleRepository */
+		$backendModuleRepository = GeneralUtility::makeInstance(BackendModuleRepository::class);
 		/** @var \TYPO3\CMS\Backend\Domain\Model\Module\BackendModule $userModuleMenu */
 		$userModuleMenu = $backendModuleRepository->findByModuleName('user');
 		if ($userModuleMenu != FALSE && $userModuleMenu->getChildren()->count() > 0) {
 			foreach ($userModuleMenu->getChildren() as $module) {
+				/** @var BackendModule $module */
 				$moduleIcon = $module->getIcon();
-				$html[] = '
-					<li id="' . $module->getName() . '" class="t3-menuitem-submodule submodule mod-' . $module->getName() . '" data-modulename="' . $module->getName() . '" data-navigationcomponentid="' . $module->getNavigationComponentId() . '" data-navigationframescript="' . $module->getNavigationFrameScript() . '" data-navigationframescriptparameters="' . $module->getNavigationFrameScriptParameters() . '">
-						<a title="' .$module->getDescription() . '" href="' . $module->getLink() . '" class="modlink">
-							<span class="submodule-icon">' . ($moduleIcon['html'] ?: $moduleIcon['html']) . '</span>
-							<span class="submodule-label">' . $module->getTitle() . '</span>
-						</a>
-					</li>';
+				$dropdown[] ='<li'
+					. ' id="' . $module->getName() . '"'
+					. ' class="t3-menuitem-submodule submodule mod-' . $module->getName() . '" '
+					. ' data-modulename="' . $module->getName() . '"'
+					. ' data-navigationcomponentid="' . $module->getNavigationComponentId() . '"'
+					. ' data-navigationframescript="' . $module->getNavigationFrameScript() . '"'
+					. ' data-navigationframescriptparameters="' . $module->getNavigationFrameScriptParameters() . '"'
+					. '>';
+				$dropdown[] = '<a title="' .$module->getDescription() . '" href="' . $module->getLink() . '" class="modlink">';
+				$dropdown[] = '<span class="submodule-icon">' . ($moduleIcon['html'] ?: $moduleIcon['html']) . '</span>';
+				$dropdown[] = '<span class="submodule-label">' . $module->getTitle() . '</span>';
+				$dropdown[] = '</a>';
+				$dropdown[] = '</li>';
 			}
-			$html[] = '<li class="divider"></li>';
+			$dropdown[] = '<li class="divider"></li>';
 		}
 
-		// logout button
-		$buttonLabel = 'LLL:EXT:lang/locallang_core.xlf:' . ($GLOBALS['BE_USER']->user['ses_backuserid'] ? 'buttons.exit' : 'buttons.logout');
-		$html[] = '<li><a href="logout.php" target="_top">' . $GLOBALS['LANG']->sL($buttonLabel, TRUE) . '</a></li>';
+		// Logout button
+		$buttonLabel = 'LLL:EXT:lang/locallang_core.xlf:' . ($backendUser->user['ses_backuserid'] ? 'buttons.exit' : 'buttons.logout');
+		$dropdown[] = '<li>';
+		$dropdown[] = '<a href="logout.php" target="_top">';
+		$dropdown[] = $languageService->sL($buttonLabel, TRUE);
+		$dropdown[] = '</a>';
+		$dropdown[] = '</li>';
 
-		$html[] = '</ul>';
+		$dropdown[] = '</ul>';
 
-		return implode(LF, $html);
+		return implode(LF, $dropdown);
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
+	 * Returns an additional class if user is in "switch user" mode
 	 *
-	 * @return string List item HTML attibutes
+	 * @return array
 	 */
 	public function getAdditionalAttributes() {
-		if ($GLOBALS['BE_USER']->user['ses_backuserid']) {
-			return 'su-user';
+		$result = array();
+		if ($this->getBackendUser()->user['ses_backuserid']) {
+			$result['class'] = 'su-user';
 		}
+		return $result;
 	}
 
 	/**
-	 * Return attribute id name
+	 * This item has a drop down
 	 *
-	 * @return string The name of the ID attribute
+	 * @return bool
 	 */
-	public function getIdAttribute() {
-		return 'topbar-user-menu';
+	public function hasDropDown() {
+		return TRUE;
 	}
 
 	/**
-	 * Returns extra classes
+	 * Position relative to others
 	 *
-	 * @return array
+	 * @return int
 	 */
-	public function getExtraClasses() {
-		return array();
+	public function getIndex() {
+		return 80;
 	}
 
 	/**
-	 * This item has a drop down
+	 * Returns the current BE user.
 	 *
-	 * @return bool
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
 	 */
-	public function hasDropDown() {
-		return TRUE;
+	protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
 	}
 
 	/**
-	 * Position relative to others
+	 * Returns LanguageService
 	 *
-	 * @return int
+	 * @return \TYPO3\CMS\Lang\LanguageService
 	 */
-	public function getIndex() {
-		return 80;
+	protected function getLanguageService() {
+		return $GLOBALS['LANG'];
 	}
 
 }
diff --git a/typo3/sysext/backend/Classes/Controller/BackendController.php b/typo3/sysext/backend/Classes/Controller/BackendController.php
index cd1f5bd44e67..07c7662b5051 100644
--- a/typo3/sysext/backend/Classes/Controller/BackendController.php
+++ b/typo3/sysext/backend/Classes/Controller/BackendController.php
@@ -157,7 +157,7 @@ class BackendController {
 		$toolbarItemInstances = array();
 		$classNameRegistry = $GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'];
 		foreach ($classNameRegistry as $className) {
-			$toolbarItemInstance = GeneralUtility::makeInstance($className, $this);
+			$toolbarItemInstance = GeneralUtility::makeInstance($className);
 			if (!$toolbarItemInstance instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
 				throw new \RuntimeException(
 					'class ' . $className . ' is registered as toolbar item but does not implement'
@@ -172,10 +172,10 @@ class BackendController {
 					1415968498
 				);
 			}
+			// Find next free position in array
 			while(array_key_exists($index, $toolbarItemInstances)) {
 				$index++;
 			}
-			// Find next free position in
 			$toolbarItemInstances[$index] = $toolbarItemInstance;
 		}
 		ksort($toolbarItemInstances);
@@ -200,11 +200,9 @@ class BackendController {
 					<div class="navbar-header" id="typo3-logo">' .
 						$logo->render() .
 					'</div>
-					<div id="typo3-top">
-						<ul class="nav navbar-nav navbar-right typo3-top-toolbar" id="typo3-toolbar">' .
-							$this->renderToolbar() .
-						'</ul>
-					</div>
+					<div id="typo3-top">' .
+						$this->renderToolbar() .
+					'</div>
 				</div>
 			</div>' .
 			$this->generateModuleMenu();
@@ -315,26 +313,57 @@ class BackendController {
 	 * @return string top toolbar elements as HTML
 	 */
 	protected function renderToolbar() {
-		$toolbar = '';
+		$toolbar = array();
+		$toolbar[] = '<ul class="nav navbar-nav navbar-right typo3-top-toolbar" id="typo3-toolbar">';
 		foreach ($this->toolbarItems as $toolbarItem) {
-			$menu = $toolbarItem->render();
-			if ($menu) {
-				// @TODO: Should throw as soon as "loading by convention" is implemented
-				if ($toolbarItem instanceof \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface) {
-					$classes = $toolbarItem->getExtraClasses();
-					if ($toolbarItem->hasDropdown()) {
-						$classes[] = 'dropdown';
-					}
-
-					$class = implode(' ', $classes);
-					if ($class !== '') {
-						$class = ' class="' . $class . '"';
-					}
-					$toolbar .= '<li' . $class . ' id="' . $toolbarItem->getIdAttribute() . '"' . $toolbarItem->getAdditionalAttributes() . '>' . $menu . '</li>';
+			/** @var \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface $toolbarItem */
+			if ($toolbarItem->checkAccess()) {
+				$hasDropDown = (bool)$toolbarItem->hasDropDown();
+				$additionalAttributes = (array)$toolbarItem->getAdditionalAttributes();
+
+				$liAttributes = array();
+
+				// Merge class: Add dropdown class if hasDropDown, add classes from additonal attributes
+				$classes = array();
+				if ($hasDropDown) {
+					$classes[] = 'dropdown';
 				}
+				if (isset($additionalAttributes['class'])) {
+					$classes[] = $additionalAttributes['class'];
+					unset($additionalAttributes['class']);
+				}
+				$liAttributes[] = 'class="' . implode(' ', $classes) . '"';
+
+				// Add further attributes
+				foreach($additionalAttributes as $name => $value) {
+					$liAttributes[] = $name . '="' . $value . '"';
+				}
+
+				// Create a unique id from class name
+				$className = get_class($toolbarItem);
+				$className = GeneralUtility::underscoredToLowerCamelCase($className);
+				$className = GeneralUtility::camelCaseToLowerCaseUnderscored($className);
+				$className = str_replace(array('_', '\\'), '-', $className);
+				$liAttributes[] = 'id="' . $className . '"';
+
+				$toolbar[] = '<li ' . implode(' ', $liAttributes) . '>';
+
+				if ($hasDropDown) {
+					$toolbar[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
+					$toolbar[] = $toolbarItem->getItem();
+					$toolbar[] = '</a>';
+					$toolbar[] = '<div class="dropdown-menu" role="menu">';
+					$toolbar[] = $toolbarItem->getDropDown();
+					$toolbar[] = '</div>';
+				} else {
+					$toolbar[] = $toolbarItem->getItem();
+				}
+				$toolbar[] = '</li>';
 			}
 		}
-		return $toolbar;
+		$toolbar[] = '</ul>';
+
+		return implode(LF, $toolbar);
 	}
 
 	/**
diff --git a/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php b/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php
index 03fa952897a3..1b475e306cb0 100644
--- a/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php
+++ b/typo3/sysext/backend/Classes/Toolbar/ToolbarItemInterface.php
@@ -22,13 +22,6 @@ namespace TYPO3\CMS\Backend\Toolbar;
  */
 interface ToolbarItemInterface {
 
-	/**
-	 * Constructor that receives a back reference to the backend
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController TYPO3 backend object reference
-	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL);
-
 	/**
 	 * Checks whether the user has access to this toolbar item
 	 *
@@ -37,38 +30,36 @@ interface ToolbarItemInterface {
 	public function checkAccess();
 
 	/**
-	 * Renders the toolbar item
+	 * Render "item" part of this toolbar
 	 *
-	 * @return string The toolbar item rendered as HTML string
+	 * @return string Toolbar item HTML
 	 */
-	public function render();
+	public function getItem();
 
 	/**
-	 * Return attribute id name
+	 * TRUE if this toolbar item has a collapsible drop down
 	 *
-	 * @return string The name of the ID attribute
+	 * @return bool
 	 */
-	public function getIdAttribute();
+	public function hasDropDown();
 
 	/**
-	 * Returns extra classes
+	 * Render "drop down" part of this toolbar
 	 *
-	 * @return array
+	 * @return string Drop down HTML
 	 */
-	public function getExtraClasses();
+	public function getDropDown();
 
 	/**
-	 * TRUE if this toolbar item has a collapsible drop down
+	 * Returns an array with additional attributes added to containing <li> tag of the item.
 	 *
-	 * @return bool
-	 */
-//	public function hasDropDrown();
-// TODO put that back in action and fix all classes by 2014-11-15
-	/**
-	 * Returns additional attributes for the list item in the toolbar
+	 * Typical usages are additional css classes and data-* attributes, classes may be merged
+	 * with other classes needed by the framework. Do NOT set an id attribute here.
 	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
+	 * array(
+	 *     'class' => 'my-class',
+	 *     'data-foo' => '42',
+	 * )
 	 *
 	 * @return string List item HTML attibutes
 	 */
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js
index 24bf19d9d950..d9fd9f783681 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ClearCacheMenu.js
@@ -18,11 +18,11 @@ define('TYPO3/CMS/Backend/Toolbar/ClearCacheMenu', ['jquery'], function($) {
 
 	var ClearCacheMenu = {
 		$spinnerElement: $('<span>', {
-			'class': 't3-icon fa fa-circle-o-notch spinner fa-spin'
+			'class': 't3-icon fa fa-circle-o-notch fa-spin'
 		}),
 		options: {
-			containerSelector: '#clear-cache-actions-menu',
-			menuItemSelector: '.dropdown-menu li a',
+			containerSelector: '#typo3-cms-backend-backend-toolbaritems-clearcachetoolbaritem',
+			menuItemSelector: '.dropdown-menu a',
 			toolbarIconSelector: '.dropdown-toggle span.t3-icon'
 		}
 	};
@@ -32,7 +32,7 @@ define('TYPO3/CMS/Backend/Toolbar/ClearCacheMenu', ['jquery'], function($) {
 	 * the clear cache call
 	 */
 	ClearCacheMenu.initializeEvents = function() {
-		$(ClearCacheMenu.options.menuItemSelector, ClearCacheMenu.options.containerSelector).on('click', function(evt) {
+		$(ClearCacheMenu.options.containerSelector).on('click', ClearCacheMenu.options.menuItemSelector, function(evt) {
 			evt.preventDefault();
 			var ajaxUrl = $(this).attr('href');
 			if (ajaxUrl) {
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js
index e9fcdc10cdf6..265bbf97faa0 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/Toolbar/ShortcutMenu.js
@@ -21,7 +21,7 @@ define('TYPO3/CMS/Backend/Toolbar/ShortcutMenu', ['jquery'], function($) {
 			class: 't3-icon fa fa-circle-o-notch fa-spin'
 		}),
 		options: {
-			containerSelector: '#shortcut-menu',
+			containerSelector: '#typo3-cms-backend-backend-toolbaritems-shortcuttoolbaritem',
 			toolbarIconSelector: '.dropdown-toggle span.t3-icon',
 			toolbarMenuSelector: '.dropdown-menu',
 			shortcutItemSelector: '.dropdown-menu .shortcut',
diff --git a/typo3/sysext/backend/ext_localconf.php b/typo3/sysext/backend/ext_localconf.php
index f6f76ff2dc35..54f61079b8cf 100644
--- a/typo3/sysext/backend/ext_localconf.php
+++ b/typo3/sysext/backend/ext_localconf.php
@@ -10,10 +10,10 @@ if (TYPO3_MODE === 'BE') {
 	);
 
 	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ClearCacheToolbarItem';
+	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\HelpToolbarItem';
 	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\LiveSearchToolbarItem';
 	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem';
 	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\UserToolbarItem';
-	$GLOBALS['TYPO3_CONF_VARS']['BE']['toolbarItems'][] = 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\HelpToolbarItem';
 }
 
 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default'] = 'TYPO3\\CMS\\Core\\FrontendEditing\\FrontendEditingController';
diff --git a/typo3/sysext/core/Classes/Page/PageRenderer.php b/typo3/sysext/core/Classes/Page/PageRenderer.php
index c1109ee7a791..ec1651eaf507 100644
--- a/typo3/sysext/core/Classes/Page/PageRenderer.php
+++ b/typo3/sysext/core/Classes/Page/PageRenderer.php
@@ -1671,7 +1671,7 @@ class PageRenderer implements \TYPO3\CMS\Core\SingletonInterface {
 	 *		"Backend": Extension Name
 	 *		"FormEngine": FileName in the Resources/Public/JavaScript folder
 	 *
-	 * @param $mainModuleName must be in the form of "TYPO3/CMS/PackageName/ModuleName" e.g. "TYPO3/CMS/Backend/FormEngine"
+	 * @param string $mainModuleName Must be in the form of "TYPO3/CMS/PackageName/ModuleName" e.g. "TYPO3/CMS/Backend/FormEngine"
 	 * @return void
 	 */
 	public function loadRequireJsModule($mainModuleName) {
diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php
index 9e9754297fe4..249c561981c3 100644
--- a/typo3/sysext/core/Configuration/DefaultConfiguration.php
+++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php
@@ -635,23 +635,23 @@ return array(
 				'csrfTokenCheck' => TRUE
 			),
 			'ShortcutMenu::getShortcutEditForm' => array(
-				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem->getAjaxShortcutEditForm',
+				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem->getAjaxShortcutEditForm',
 				'csrfTokenCheck' => TRUE
 			),
 			'ShortcutMenu::saveShortcut' => array(
-				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem->setAjaxShortcut',
+				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem->setAjaxShortcut',
 				'csrfTokenCheck' => TRUE
 			),
 			'ShortcutMenu::render' => array(
-				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem->renderAjaxMenu',
+				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem->renderAjaxMenu',
 				'csrfTokenCheck' => TRUE
 			),
 			'ShortcutMenu::delete' => array(
-				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem->deleteAjaxShortcut',
+				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem->deleteAjaxShortcut',
 				'csrfTokenCheck' => TRUE
 			),
 			'ShortcutMenu::create' => array(
-				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Toolbar\\ShortcutToolbarItem->createAjaxShortcut',
+				'callbackMethod' => 'TYPO3\\CMS\\Backend\\Backend\\ToolbarItems\\ShortcutToolbarItem->createAjaxShortcut',
 				'csrfTokenCheck' => TRUE
 			),
 			'ModuleMenu::reload' => array(
diff --git a/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php b/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
index b678cdac8976..bdacab2c8a8b 100644
--- a/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
+++ b/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
@@ -15,20 +15,16 @@ namespace TYPO3\CMS\Opendocs\Backend\ToolbarItems;
  */
 
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Utility\IconUtility;
 
 /**
- * Adding a list of all open documents of a user to the backend.php
+ * Alist of all open documents
  *
  * @author Benjamin Mack <benni@typo3.org>
  * @author Ingo Renner <ingo@typo3.org>
  */
 class OpendocsToolbarItem implements ToolbarItemInterface {
 
-	/**
-	 * @var \TYPO3\CMS\Backend\Controller\BackendController
-	 */
-	protected $backendReference;
-
 	/**
 	 * @var array
 	 */
@@ -40,19 +36,14 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 	protected $recentDocs;
 
 	/**
-	 * @var string
-	 */
-	protected $EXTKEY = 'opendocs';
-
-	/**
-	 * Constructor, loads the documents from the user control
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController TYPO3 backend object reference
+	 * Constructor
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
-		$GLOBALS['LANG']->includeLLFile('EXT:opendocs/locallang_opendocs.xlf');
-		$this->backendReference = $backendReference;
+	public function __construct() {
+		$this->getLanguageService()->includeLLFile('EXT:opendocs/locallang_opendocs.xlf');
 		$this->loadDocsFromUserSession();
+		$pageRenderer = $this->getPageRenderer();
+		$pageRenderer->loadRequireJsModule('TYPO3/CMS/Opendocs/Toolbar/OpendocsMenu');
+		$pageRenderer->addCssFile(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('opendocs') . '/Resources/Public/Css/opendocs.css');
 	}
 
 	/**
@@ -61,7 +52,7 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 	 * @return bool TRUE if user has access, FALSE if not
 	 */
 	public function checkAccess() {
-		$conf = $GLOBALS['BE_USER']->getTSConfig('backendToolbarItem.tx_opendocs.disabled');
+		$conf = $this->getBackendUser()->getTSConfig('backendToolbarItem.tx_opendocs.disabled');
 		return $conf['value'] != 1;
 	}
 
@@ -71,47 +62,39 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 	 * @return void
 	 */
 	public function loadDocsFromUserSession() {
-		list($this->openDocs, ) = $GLOBALS['BE_USER']->getModuleData('alt_doc.php', 'ses');
-		$this->recentDocs = $GLOBALS['BE_USER']->getModuleData('opendocs::recent');
+		$backendUser = $this->getBackendUser();
+		list($this->openDocs, ) = $backendUser->getModuleData('alt_doc.php', 'ses');
+		$this->recentDocs = $backendUser->getModuleData('opendocs::recent');
 	}
 
 	/**
-	 * Renders the toolbar item and the initial menu
+	 * Render toolbar icon
 	 *
-	 * @return string The toolbar item including the initial menu content as HTML
+	 * @return string HTML
 	 */
-	public function render() {
-		$this->addJavascriptToBackend();
-		$this->addCssToBackend();
+	public function getItem() {
 		$numDocs = count($this->openDocs);
-		$opendocsMenu = array();
-		$title = $GLOBALS['LANG']->getLL('toolbaritem', TRUE);
+		$title = $this->getLanguageService()->getLL('toolbaritem', TRUE);
 
-		// Toolbar item icon
-		$opendocsMenu[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">';
-		$opendocsMenu[] = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('apps-toolbar-menu-opendocs', array('title' => $title));
+		$opendocsMenu = array();
+		$opendocsMenu[] = IconUtility::getSpriteIcon('apps-toolbar-menu-opendocs', array('title' => $title));
 		$opendocsMenu[] = '<span class="badge" id="tx-opendocs-counter">' . $numDocs . '</span>';
-		$opendocsMenu[] = '</a>';
 
-		// Toolbar item menu and initial content
-		$opendocsMenu[] = '<ul class="dropdown-menu" role="menu">';
-		$opendocsMenu[] = $this->renderMenu();
-		$opendocsMenu[] = '</ul>';
 		return implode(LF, $opendocsMenu);
 	}
 
 	/**
-	 * renders the pure contents of the menu
+	 * Render drop down
 	 *
-	 * @return string The menu's content
+	 * @return string HTML
 	 */
-	public function renderMenu() {
+	public function getDropDown() {
+		$languageService = $this->getLanguageService();
 		$openDocuments = $this->openDocs;
 		$recentDocuments = $this->recentDocs;
 		$entries = array();
-		$content = '';
 		if (count($openDocuments)) {
-			$entries[] = '<li class="dropdown-header">' . $GLOBALS['LANG']->getLL('open_docs', TRUE) . '</li>';
+			$entries[] = '<li class="dropdown-header">' . $languageService->getLL('open_docs', TRUE) . '</li>';
 			$i = 0;
 			foreach ($openDocuments as $md5sum => $openDocument) {
 				$i++;
@@ -120,7 +103,7 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 		}
 		// If there are "recent documents" in the list, add them
 		if (count($recentDocuments)) {
-			$entries[] = '<li class="dropdown-header">' . $GLOBALS['LANG']->getLL('recent_docs', TRUE) . '</li>';
+			$entries[] = '<li class="dropdown-header">' . $languageService->getLL('recent_docs', TRUE) . '</li>';
 			$i = 0;
 			foreach ($recentDocuments as $md5sum => $recentDocument) {
 				$i++;
@@ -128,9 +111,9 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 			}
 		}
 		if (count($entries)) {
-			$content = implode('', $entries);
+			$content = '<ul>' . implode('', $entries) . '</ul>';
 		} else {
-			$content = '<li class="noOpenDocs">' . $GLOBALS['LANG']->getLL('no_docs', TRUE) . '</li>';
+			$content = '<ul><li class="noOpenDocs">' . $languageService->getLL('no_docs', TRUE) . '</li></ul>';
 		}
 		return $content;
 	}
@@ -138,9 +121,13 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 	/**
 	 * Returns the recent documents list as an array
 	 *
+	 * @param array $document
+	 * @param string $md5sum
+	 * @param bool $isRecentDoc
+	 * @param bool $isFirstDoc
 	 * @return array All recent documents as list-items
 	 */
-	public function renderMenuEntry($document, $md5sum, $isRecentDoc = FALSE, $isFirstDoc = FALSE) {
+	protected function renderMenuEntry($document, $md5sum, $isRecentDoc = FALSE, $isFirstDoc = FALSE) {
 		$table = $document[3]['table'];
 		$uid = $document[3]['uid'];
 		$record = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordWSOL($table, $uid);
@@ -181,32 +168,11 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
+	 * No additional attributes
 	 *
 	 * @return string List item HTML attibutes
 	 */
 	public function getAdditionalAttributes() {
-		return '';
-	}
-
-	/**
-	 * Return attribute id name
-	 *
-	 * @return string The name of the ID attribute
-	 */
-	public function getIdAttribute() {
-		return 'tx-opendocs-menu';
-	}
-
-	/**
-	 * Returns extra classes
-	 *
-	 * @return array
-	 */
-	public function getExtraClasses() {
 		return array();
 	}
 
@@ -219,26 +185,6 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 		return TRUE;
 	}
 
-	/**
-	 * Adds the necessary javascript to the backend
-	 *
-	 * @return void
-	 */
-	protected function addJavascriptToBackend() {
-		$this->backendReference->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Opendocs/Toolbar/OpendocsMenu');
-	}
-
-	/**
-	 * Adds the necessary CSS to the backend
-	 *
-	 * @return void
-	 */
-	protected function addCssToBackend() {
-		$this->backendReference->addCssFile(
-			'opendocs',
-				\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath($this->EXTKEY) . '/Resources/Public/Css/opendocs.css'
-		);
-	}
 
 	/*******************
 	 ***    HOOKS    ***
@@ -295,8 +241,7 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 	 * @return void
 	 */
 	public function renderAjax($params = array(), \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj = NULL) {
-		$menuContent = $this->renderMenu();
-		$ajaxObj->addContent('opendocsMenu', $menuContent);
+		$ajaxObj->addContent('opendocsMenu', $this->getDropDown());
 	}
 
 	/**
@@ -308,4 +253,42 @@ class OpendocsToolbarItem implements ToolbarItemInterface {
 		return 30;
 	}
 
+	/**
+	 * Returns the current BE user.
+	 *
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+	 */
+	protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
+	}
+
+	/**
+	 * Returns current PageRenderer
+	 *
+	 * @return \TYPO3\CMS\Core\Page\PageRenderer
+	 */
+	protected function getPageRenderer() {
+		/** @var  \TYPO3\CMS\Backend\Template\DocumentTemplate $documentTemplate */
+		$documentTemplate = $GLOBALS['TBE_TEMPLATE'];
+		return $documentTemplate->getPageRenderer();
+	}
+
+	/**
+	 * Returns LanguageService
+	 *
+	 * @return \TYPO3\CMS\Lang\LanguageService
+	 */
+	protected function getLanguageService() {
+		return $GLOBALS['LANG'];
+	}
+
+	/**
+	 * Return DatabaseConnection
+	 *
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+	 */
+	protected function getDatabaseConnection() {
+		return $GLOBALS['TYPO3_DB'];
+	}
+
 }
diff --git a/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js b/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js
index 4f57705490e9..abb59efdd2fb 100644
--- a/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js
+++ b/typo3/sysext/opendocs/Resources/Public/JavaScript/Toolbar/OpendocsMenu.js
@@ -22,7 +22,7 @@ define('TYPO3/CMS/Opendocs/Toolbar/OpendocsMenu', ['jquery'], function($) {
 			'class': 't3-icon fa fa-circle-o-notch spinner fa-spin'
 		}),
 		options: {
-			containerSelector: '#tx-opendocs-menu',
+			containerSelector: '#typo3-cms-opendocs-backend-toolbaritems-opendocstoolbaritem',
 			hashDataAttributeName: 'opendocsidentifier',
 			closeSelector: '.close',
 			menuContainerSelector: '.dropdown-menu',
diff --git a/typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php b/typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php
index d106c1c3f59c..26f08f2d8894 100644
--- a/typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php
+++ b/typo3/sysext/sys_action/Classes/Backend/ToolbarItems/ActionToolbarItem.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\SysAction\Backend\ToolbarItems;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use TYPO3\CMS\Backend\Utility\IconUtility;
 
 /**
  * Adds action links to the backend's toolbar
@@ -25,73 +26,68 @@ use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 class ActionToolbarItem implements ToolbarItemInterface {
 
 	/**
-	 * @var \TYPO3\CMS\Backend\Controller\BackendController
+	 * @var array List of action entries
 	 */
-	protected $backendReference;
-
-	/**
-	 * @var string
-	 */
-	protected $extensionKey = 'sys_action';
+	protected $actionEntries = array();
 
 	/**
 	 * Constructor
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
-		$GLOBALS['LANG']->includeLLFile('EXT:sys_action/locallang.xlf');
-		$this->backendReference = $backendReference;
+	public function __construct() {
+		$this->getLanguageService()->includeLLFile('EXT:sys_action/locallang.xlf');
+		$this->initializeActionEntries();
 	}
 
 	/**
-	 * Sets the backend reference
+	 * Render toolbar icon
 	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference Backend object reference
-	 * @return void
+	 * @return string HTML
 	 */
-	public function setBackend(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference) {
-		$this->backendReference = $backendReference;
+	public function getItem() {
+		return IconUtility::getSpriteIcon(
+			'apps-toolbar-menu-actions',
+			array(
+				'title' => $this->getLanguageService()->getLL('action_toolbaritem', TRUE)
+			)
+		);
 	}
 
 	/**
-	 * Renders the toolbar menu
+	 * Render drop down
 	 *
-	 * @return string The rendered backend menu
-	 * @author Ingo Renner <ingo@typo3.org>
+	 * @return string HTML
 	 */
-	public function render() {
+	public function getDropDown() {
 		$actionMenu = array();
-		$actionEntries = $this->getActionEntries();
-		if ($actionEntries) {
-			$title = $GLOBALS['LANG']->getLL('action_toolbaritem', TRUE);
-			$actionMenu[] = '<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('apps-toolbar-menu-actions', array('title' => $title)) . '</a>';
-			$actionMenu[] = '<ul class="dropdown-menu" role="menu">';
-			foreach ($actionEntries as $linkConf) {
-				$actionMenu[] = '<li><a href="' . htmlspecialchars($linkConf[1]) . '" target="content">' . $linkConf[2] . htmlspecialchars($linkConf[0]) . '</a></li>';
-			}
-			$actionMenu[] = '</ul>';
-			return implode(LF, $actionMenu);
-		} else {
-			return '';
+		$actionMenu[] = '<ul>';
+		foreach ($this->actionEntries as $linkConf) {
+			$actionMenu[] = '<li>';
+			$actionMenu[] = '<a href="' . htmlspecialchars($linkConf[1]) . '" target="content">';
+			$actionMenu[] = $linkConf[2] . htmlspecialchars($linkConf[0]);
+			$actionMenu[] = '</a>';
+			$actionMenu[] = '</li>';
 		}
+		$actionMenu[] = '</ul>';
+		return implode(LF, $actionMenu);
 	}
 
 	/**
 	 * Gets the entries for the action menu
 	 *
 	 * @return array Array of action menu entries
-	 * @author Steffen Kamper <info@sk-typo3.de>
-	 * @author Ingo Renner <ingo@typo3.org>
 	 */
-	protected function getActionEntries() {
+	protected function initializeActionEntries() {
+		$backendUser = $this->getBackendUser();
+		$databaseConnection = $this->getDatabaseConnection();
 		$actions = array();
-		if ($GLOBALS['BE_USER']->isAdmin()) {
-			$queryResource = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_action', 'pid = 0 AND hidden=0', '', 'sys_action.sorting');
+		if ($backendUser->isAdmin()) {
+			$queryResource = $databaseConnection->exec_SELECTquery('*', 'sys_action', 'pid = 0 AND hidden=0', '', 'sys_action.sorting');
 		} else {
 			$groupList = 0;
-			if ($GLOBALS['BE_USER']->groupList) {
-				$groupList = $GLOBALS['BE_USER']->groupList;
+			if ($backendUser->groupList) {
+				$groupList = $backendUser->groupList;
 			}
-			$queryResource = $GLOBALS['TYPO3_DB']->exec_SELECT_mm_query(
+			$queryResource = $databaseConnection->exec_SELECT_mm_query(
 				'sys_action.*',
 				'sys_action',
 				'sys_action_asgr_mm',
@@ -103,45 +99,24 @@ class ActionToolbarItem implements ToolbarItemInterface {
 		}
 
 		if ($queryResource) {
-			while ($actionRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($queryResource)) {
+			while ($actionRow = $databaseConnection->sql_fetch_assoc($queryResource)) {
 				$actions[] = array(
 					$actionRow['title'],
 					BackendUtility::getModuleUrl('user_task') . '&SET[mode]=tasks&SET[function]=sys_action.TYPO3\\CMS\\SysAction\\ActionTask&show=' . $actionRow['uid'],
-					\TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForRecord('sys_action', $actionRow)
+					IconUtility::getSpriteIconForRecord('sys_action', $actionRow)
 				);
 			}
-			$GLOBALS['TYPO3_DB']->sql_free_result($queryResource);
+			$databaseConnection->sql_free_result($queryResource);
 		}
-		return $actions;
-	}
-
-	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
-	 *
-	 * @return string List item HTML attibutes
-	 */
-	public function getAdditionalAttributes() {
-		return '';
+		$this->actionEntries = $actions;
 	}
 
 	/**
-	 * Return attribute id name
-	 *
-	 * @return string The name of the ID attribute
-	 */
-	public function getIdAttribute() {
-		return 'tx-sys-action-menu';
-	}
-
-	/**
-	 * Returns extra classes
+	 * This toolbar needs no additional attributes
 	 *
 	 * @return array
 	 */
-	public function getExtraClasses() {
+	public function getAdditionalAttributes() {
 		return array();
 	}
 
@@ -155,13 +130,16 @@ class ActionToolbarItem implements ToolbarItemInterface {
 	}
 
 	/**
-	 * Checks if user has access to the sys action menu
+	 * This toolbar is rendered if there are action entries, no further user restriction
 	 *
-	 * @return bool TRUE if the user has access, FALSE otherwise
+	 * @return bool TRUE
 	 */
 	public function checkAccess() {
-		// Taskcenter is enabled for everybody
-		return TRUE;
+		$result = FALSE;
+		if (count($this->actionEntries)) {
+			$result = TRUE;
+		}
+		return $result;
 	}
 
 	/**
@@ -173,4 +151,31 @@ class ActionToolbarItem implements ToolbarItemInterface {
 		return 35;
 	}
 
+	/**
+	 * Returns the current BE user.
+	 *
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+	 */
+	protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
+	}
+
+	/**
+	 * Returns LanguageService
+	 *
+	 * @return \TYPO3\CMS\Lang\LanguageService
+	 */
+	protected function getLanguageService() {
+		return $GLOBALS['LANG'];
+	}
+
+	/**
+	 * Return DatabaseConnection
+	 *
+	 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+	 */
+	protected function getDatabaseConnection() {
+		return $GLOBALS['TYPO3_DB'];
+	}
+
 }
diff --git a/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_topbar.less b/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_topbar.less
index 8be0193b6bee..bff82fc4368f 100644
--- a/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_topbar.less
+++ b/typo3/sysext/t3skin/Resources/Private/Styles/TYPO3/_topbar.less
@@ -69,12 +69,30 @@ Topbar
 			.dropdown-menu {
 				background-color: @navbar-inverse-link-active-bg;
 				color: @navbar-inverse-link-active-color;
-				border: 0;
-				margin: 0;
+				border: none;
 
-				.active {
-					a {
-						background-color: darken(@navbar-inverse-link-active-bg, 15%);
+				// Dropdown-menu with UL
+				> ul {
+					.list-unstyled;
+
+					> li {
+						> a {
+							color: @navbar-inverse-link-active-color;
+							display: block;
+							padding: 3px 20px;
+							clear: both;
+							font-weight: normal;
+							line-height: @line-height-base;
+							white-space: nowrap;
+						}
+
+						&.active {
+							> a {
+								background-color: darken(@navbar-inverse-link-active-bg, 15%);
+
+							}
+
+						}
 					}
 				}
 
diff --git a/typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css b/typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css
index 0e818d792ab0..c6e2ec48c35f 100644
--- a/typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css
+++ b/typo3/sysext/t3skin/Resources/Public/Css/visual/t3skin.css
@@ -11419,10 +11419,22 @@ Topbar
 #typo3-topbar #typo3-top-container #typo3-toolbar .dropdown-menu {
   background-color: #4e4e4e;
   color: #ffffff;
-  border: 0;
-  margin: 0;
+  border: none;
+}
+#typo3-topbar #typo3-top-container #typo3-toolbar .dropdown-menu > ul {
+  padding-left: 0;
+  list-style: none;
+}
+#typo3-topbar #typo3-top-container #typo3-toolbar .dropdown-menu > ul > li > a {
+  color: #ffffff;
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.5;
+  white-space: nowrap;
 }
-#typo3-topbar #typo3-top-container #typo3-toolbar .dropdown-menu .active a {
+#typo3-topbar #typo3-top-container #typo3-toolbar .dropdown-menu > ul > li.active > a {
   background-color: #282828;
 }
 #typo3-topbar #typo3-top-container #typo3-toolbar .dropdown-menu li a,
diff --git a/typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php b/typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php
index c980baa78ebe..eaa79de389c8 100644
--- a/typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php
+++ b/typo3/sysext/workspaces/Classes/Backend/ToolbarItems/WorkspaceSelectorToolbarItem.php
@@ -15,32 +15,24 @@ namespace TYPO3\CMS\Workspaces\Backend\ToolbarItems;
  */
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
+use \TYPO3\CMS\Workspaces\Service\WorkspaceService;
+use TYPO3\CMS\Backend\Utility\IconUtility;
 
 /**
  * Class to render the workspace selector
  *
  * @author Ingo Renner <ingo@typo3.org>
  */
-class WorkspaceSelectorToolbarItem implements \TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface {
-
-	/**
-	 * @var \TYPO3\CMS\Backend\Controller\BackendController
-	 */
-	protected $backendReference;
-
-	/**
-	 * @var bool|null
-	 */
-	protected $checkAccess = NULL;
+class WorkspaceSelectorToolbarItem implements ToolbarItemInterface {
 
 	/**
 	 * Constructor
-	 *
-	 * @param \TYPO3\CMS\Backend\Controller\BackendController $backendReference TYPO3 backend object reference
 	 */
-	public function __construct(\TYPO3\CMS\Backend\Controller\BackendController &$backendReference = NULL) {
-		$this->backendReference = $backendReference;
-		$this->backendReference->getPageRenderer()->addInlineLanguageLabel('Workspaces.workspaceTitle', \TYPO3\CMS\Workspaces\Service\WorkspaceService::getWorkspaceTitle($GLOBALS['BE_USER']->workspace));
+	public function __construct() {
+		$pageRenderer = $this->getPageRenderer();
+		$pageRenderer->addInlineLanguageLabel('Workspaces.workspaceTitle', WorkspaceService::getWorkspaceTitle($this->getBackendUser()->workspace));
+		$pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Toolbar/WorkspacesMenu');
 	}
 
 	/**
@@ -49,36 +41,43 @@ class WorkspaceSelectorToolbarItem implements \TYPO3\CMS\Backend\Toolbar\Toolbar
 	 * @return bool TRUE if user has access, FALSE if not
 	 */
 	public function checkAccess() {
-		if ($this->checkAccess === NULL) {
-			/** @var \TYPO3\CMS\Workspaces\Service\WorkspaceService $wsService */
-			$wsService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
-			$availableWorkspaces = $wsService->getAvailableWorkspaces();
-			if (count($availableWorkspaces) > 0) {
-				$this->checkAccess = TRUE;
-			} else {
-				$this->checkAccess = FALSE;
-			}
+		/** @var \TYPO3\CMS\Workspaces\Service\WorkspaceService $wsService */
+		$wsService = GeneralUtility::makeInstance(WorkspaceService::class);
+		$availableWorkspaces = $wsService->getAvailableWorkspaces();
+		if (count($availableWorkspaces) > 0) {
+			$result = TRUE;
+		} else {
+			$result = FALSE;
 		}
-		return $this->checkAccess;
+		return $result;
 	}
 
 	/**
-	 * Creates the selector for workspaces
+	 * Render item
 	 *
-	 * @return string workspace selector as HTML select
+	 * @return string HTML
 	 */
-	public function render() {
-		$title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.workspace', TRUE);
-		$this->backendReference->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Workspaces/Toolbar/WorkspacesMenu');
+	public function getItem() {
+		return IconUtility::getSpriteIcon(
+			'apps-toolbar-menu-workspace',
+			array(
+				'title' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:toolbarItems.workspace', TRUE),
+			)
+		);
+	}
+
+	public function getDropDown() {
+		$backendUser = $this->getBackendUser();
+		$languageService = $this->getLanguageService();
 
 		$index = 0;
-		/** @var \TYPO3\CMS\Workspaces\Service\WorkspaceService $wsService */
-		$wsService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+		/** @var WorkspaceService $wsService */
+		$wsService = GeneralUtility::makeInstance(WorkspaceService::class);
 		$availableWorkspaces = $wsService->getAvailableWorkspaces();
-		$activeWorkspace = (int)$GLOBALS['BE_USER']->workspace;
-		$stateCheckedIcon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-status-checked');
-		$stateUncheckedIcon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('empty-empty', array(
-			'title' => $GLOBALS['LANG']->getLL('bookmark_inactive')
+		$activeWorkspace = (int)$backendUser->workspace;
+		$stateCheckedIcon = IconUtility::getSpriteIcon('status-status-checked');
+		$stateUncheckedIcon = IconUtility::getSpriteIcon('empty-empty', array(
+			'title' => $languageService->getLL('bookmark_inactive')
 		));
 
 		$workspaceSections = array(
@@ -91,23 +90,27 @@ class WorkspaceSelectorToolbarItem implements \TYPO3\CMS\Backend\Toolbar\Toolbar
 			$iconState = ($workspaceId === $activeWorkspace ? $stateCheckedIcon : $stateUncheckedIcon);
 			$classValue = ($workspaceId === $activeWorkspace ? ' class="selected"' : '');
 			$sectionName = ($index++ === 0 ? 'top' : 'items');
-			$workspaceSections[$sectionName][] = '<li' . $classValue . '>' . '<a href="backend.php?changeWorkspace=' . $workspaceId . '" data-workspaceid="' . $workspaceId . '" class="tx-workspaces-switchlink">' . $iconState . ' ' . htmlspecialchars($label) . '</a></li>';
+			$workspaceSections[$sectionName][] = '<li' . $classValue . '>'
+				. '<a href="backend.php?changeWorkspace=' . $workspaceId . '" data-workspaceid="' . $workspaceId . '" class="tx-workspaces-switchlink">'
+				. $iconState . ' ' . htmlspecialchars($label)
+				. '</a></li>';
 		}
 
 		if (!empty($workspaceSections['top'])) {
 			// Add the "Go to workspace module" link
 			// if there is at least one icon on top and if the access rights are there
-			if ($GLOBALS['BE_USER']->check('modules', 'web_WorkspacesWorkspaces')) {
-				$workspaceSections['top'][] = '<li><a target="content" data-module="web_WorkspacesWorkspaces" class="tx-workspaces-modulelink">' . $stateUncheckedIcon . ' ' . $GLOBALS['LANG']->getLL('bookmark_workspace', TRUE) . '</a></li>';
+			if ($backendUser->check('modules', 'web_WorkspacesWorkspaces')) {
+				$workspaceSections['top'][] = '<li><a target="content" data-module="web_WorkspacesWorkspaces" class="tx-workspaces-modulelink">'
+					. $stateUncheckedIcon . ' ' . $languageService->getLL('bookmark_workspace', TRUE)
+					. '</a></li>';
 			}
 		} else {
 			// no items on top (= no workspace to work in)
-			$workspaceSections['top'][] = '<li>' . $stateUncheckedIcon . ' ' . $GLOBALS['LANG']->getLL('bookmark_noWSfound', TRUE) . '</li>';
+			$workspaceSections['top'][] = '<li>' . $stateUncheckedIcon . ' ' . $languageService->getLL('bookmark_noWSfound', TRUE) . '</li>';
 		}
 
 		$workspaceMenu = array(
-			'<a href="#" class="dropdown-toggle" data-toggle="dropdown">' . \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('apps-toolbar-menu-workspace', array('title' => $title)) . '</a>',
-			'<ul class="dropdown-menu" role="menu">' ,
+			'<ul>' ,
 				implode(LF, $workspaceSections['top']),
 				(!empty($workspaceSections['items']) ? '<li class="divider"></li>' : ''),
 				implode(LF, $workspaceSections['items']),
@@ -118,51 +121,59 @@ class WorkspaceSelectorToolbarItem implements \TYPO3\CMS\Backend\Toolbar\Toolbar
 	}
 
 	/**
-	 * Returns additional attributes for the list item in the toolbar
-	 *
-	 * This should not contain the "class" or "id" attribute.
-	 * Use the methods for setting these attributes
+	 * This toolbar needs no additional attributes
 	 *
-	 * @return string List item HTML attibutes
+	 * @return array
 	 */
 	public function getAdditionalAttributes() {
-		return '';
+		return array();
 	}
 
 	/**
-	 * Return attribute id name
+	 * This item has a drop down
 	 *
-	 * @return string The name of the ID attribute
+	 * @return bool
 	 */
-	public function getIdAttribute() {
-		return 'workspace-selector-menu';
+	public function hasDropDown() {
+		return TRUE;
 	}
 
 	/**
-	 * Returns extra classes
+	 * Position relative to others
 	 *
-	 * @return array
+	 * @return int
 	 */
-	public function getExtraClasses() {
-		return array();
+	public function getIndex() {
+		return 40;
 	}
 
 	/**
-	 * This item has a drop down
+	 * Returns the current BE user.
 	 *
-	 * @return bool
+	 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
 	 */
-	public function hasDropDown() {
-		return TRUE;
+	protected function getBackendUser() {
+		return $GLOBALS['BE_USER'];
 	}
 
 	/**
-	 * Position relative to others
+	 * Returns current PageRenderer
 	 *
-	 * @return int
+	 * @return \TYPO3\CMS\Core\Page\PageRenderer
 	 */
-	public function getIndex() {
-		return 40;
+	protected function getPageRenderer() {
+		/** @var  \TYPO3\CMS\Backend\Template\DocumentTemplate $documentTemplate */
+		$documentTemplate = $GLOBALS['TBE_TEMPLATE'];
+		return $documentTemplate->getPageRenderer();
+	}
+
+	/**
+	 * Returns LanguageService
+	 *
+	 * @return \TYPO3\CMS\Lang\LanguageService
+	 */
+	protected function getLanguageService() {
+		return $GLOBALS['LANG'];
 	}
 
 }
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js
index c1e445da7f23..06ad04e3b442 100644
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js
+++ b/typo3/sysext/workspaces/Resources/Public/JavaScript/Toolbar/WorkspacesMenu.js
@@ -18,7 +18,7 @@ define('TYPO3/CMS/Workspaces/Toolbar/WorkspacesMenu', ['jquery'], function($) {
 
 	var WorkspacesMenu = {
 		options: {
-			containerSelector: '#workspace-selector-menu',
+			containerSelector: '#typo3-cms-workspaces-backend-toolbaritems-workspaceselectortoolbaritem',
 			menuItemSelector: '.dropdown-menu li a.tx-workspaces-switchlink',
 			activeMenuItemSelector: '.dropdown-menu .selected',
 			toolbarItemSelector: '.dropdown-toggle',
-- 
GitLab