diff --git a/core/modules/navigation/js/user-block.js b/core/modules/navigation/js/user-block.js deleted file mode 100644 index dd09467ba618579f08eed6d971f9af5c45bac0da..0000000000000000000000000000000000000000 --- a/core/modules/navigation/js/user-block.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file - * - * Customizes the user block to use the current username without affecting - * caching. - */ - -((Drupal, drupalSettings, once) => { - /** - * Replaces the generic 'My Account' text with the actual username. - * - * @type {Drupal~behavior} - * - * @prop {Drupal~behaviorAttach} attach - * Sets the username. - */ - Drupal.behaviors.navigationUsername = { - attach: (context, settings) => { - if (!settings?.navigation?.user) { - return; - } - once('user-block', '[data-user-block]', context).forEach((userBlock) => { - userBlock - .querySelectorAll( - '.toolbar-popover__control, .toolbar-popover__header', - ) - .forEach((button) => { - const buttonLabel = button.querySelector('[data-toolbar-text]'); - button.dataset.indexText = settings.navigation.user.charAt(0); - button.dataset.iconText = settings.navigation.user.substring(0, 2); - if (buttonLabel) { - buttonLabel.textContent = settings.navigation.user; - } - }); - }); - }, - }; -})(Drupal, drupalSettings, once); diff --git a/core/modules/navigation/navigation.libraries.yml b/core/modules/navigation/navigation.libraries.yml index 8385fba66ff219b0693f33197e6bbbd2c488cd0c..7121c6a7c5193472439ed5bf50aa84f91e4cd2f0 100644 --- a/core/modules/navigation/navigation.libraries.yml +++ b/core/modules/navigation/navigation.libraries.yml @@ -113,13 +113,3 @@ internal.safe-triangle: dependencies: - core/drupal - core/once - -internal.user-block: - # Internal library. Do not depend on it outside core nor add core usage - # beyond the Navigation module. - js: - js/user-block.js: {} - dependencies: - - core/drupal - - core/drupalSettings - - core/once diff --git a/core/modules/navigation/src/Hook/NavigationHooks.php b/core/modules/navigation/src/Hook/NavigationHooks.php index cd258fc8c95b50ee4f3945da453aa67ed203ddd2..8b2cd686bdcdc6368bc390b75d8ab671c9c90629 100644 --- a/core/modules/navigation/src/Hook/NavigationHooks.php +++ b/core/modules/navigation/src/Hook/NavigationHooks.php @@ -3,7 +3,6 @@ namespace Drupal\navigation\Hook; use Drupal\Component\Plugin\PluginBase; -use Drupal\Core\Asset\AttachedAssetsInterface; use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Config\Action\ConfigActionManager; use Drupal\Core\Extension\ModuleHandlerInterface; @@ -270,21 +269,6 @@ public function navigationWorkspaces(): array { ]; } - /** - * Implements hook_js_settings_alter(). - */ - #[Hook('js_settings_alter')] - public function jsSettingsAlter(array &$settings, AttachedAssetsInterface $assets): void { - // If Navigation's user-block library is not installed, return. - if (!in_array('navigation/internal.user-block', $assets->getLibraries())) { - return; - } - // Provide the user name in drupalSettings to allow JavaScript code to - // customize the experience for the end user, rather than the server side, - // which would break the render cache. - $settings['navigation']['user'] = $this->currentUser->getAccountName(); - } - /** * Implements hook_modules_installed(). */ diff --git a/core/modules/navigation/src/Plugin/Block/NavigationUserBlock.php b/core/modules/navigation/src/Plugin/Block/NavigationUserBlock.php index 9df0e04c5fc616cedfd0538763eef212554f8d44..39c13acec221dbc94f952382b6e037e2bd050e1a 100644 --- a/core/modules/navigation/src/Plugin/Block/NavigationUserBlock.php +++ b/core/modules/navigation/src/Plugin/Block/NavigationUserBlock.php @@ -6,13 +6,13 @@ use Drupal\Core\Block\Attribute\Block; use Drupal\Core\Block\BlockBase; +use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Menu\MenuLinkDefault; use Drupal\Core\Menu\MenuLinkTreeElement; -use Drupal\Core\Menu\MenuLinkTreeInterface; use Drupal\Core\Menu\MenuTreeParameters; -use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Security\Attribute\TrustedCallback; use Drupal\Core\StringTranslation\TranslatableMarkup; -use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\user\Entity\User; /** * Defines a user navigation block. @@ -23,103 +23,70 @@ id: 'navigation_user', admin_label: new TranslatableMarkup('User'), )] -final class NavigationUserBlock extends BlockBase implements ContainerFactoryPluginInterface { +final class NavigationUserBlock extends BlockBase { const string NAVIGATION_LINKS_MENU = 'navigation-user-links'; - /** - * Constructs a new SystemMenuBlock. - * - * @param array $configuration - * A configuration array containing information about the plugin instance. - * @param string $plugin_id - * The plugin ID for the plugin instance. - * @param array $plugin_definition - * The plugin implementation definition. - * @param \Symfony\Component\DependencyInjection\ContainerInterface $container - * The container. - * @param \Drupal\Core\Menu\MenuLinkTreeInterface $menuTree - * The menu link tree. - */ - public function __construct( - array $configuration, - $plugin_id, - $plugin_definition, - protected ContainerInterface $container, - protected MenuLinkTreeInterface $menuTree, - ) { - parent::__construct($configuration, $plugin_id, $plugin_definition); - } - /** * {@inheritdoc} */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self { - return new static( - $configuration, - $plugin_id, - $plugin_definition, - $container, - $container->get('navigation.menu_tree'), - ); + public function build(): array { + return [ + '#create_placeholder' => TRUE, + '#lazy_builder' => [static::class . '::buildLinks', [$this->configuration['label']]], + '#cache' => [ + 'keys' => ['navigation_user_block'], + ], + ]; } /** - * {@inheritdoc} + * Lazy builder callback. */ - public function build(): array { - $menu_name = static::NAVIGATION_LINKS_MENU; + #[TrustedCallback] + public static function buildLinks(string $label): array { $parameters = new MenuTreeParameters(); $parameters ->setMinDepth(0) ->setMaxDepth(2) ->onlyEnabledLinks(); - $subtree = $this->menuTree->load($menu_name, $parameters); + /** @var \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree */ + $menu_tree = \Drupal::service('navigation.menu_tree'); + $subtree = $menu_tree->load(static::NAVIGATION_LINKS_MENU, $parameters); + // Load the current user so that they can be added as a cacheable dependency + // of the final render array. + $account = User::load(\Drupal::currentUser()->id()); + + $menu_definition = [ + 'menu_name' => static::NAVIGATION_LINKS_MENU, + 'route_name' => 'user.page', + 'route_parameters' => [], + 'title' => $account->getDisplayName(), + 'description' => '', + 'options' => [], + 'provider' => 'navigation', + 'enabled' => '1', + ]; // Create a parent link that serves as a wrapper. // If the menu is removed for any reason, this item shows a link to the // user profile page as a fallback. - $link = MenuLinkDefault::create($this->container, [], 'navigation.user_links.user.wrapper', $this->menuLinkDefinition()); + $link = MenuLinkDefault::create(\Drupal::getContainer(), [], 'navigation.user_links.user.wrapper', $menu_definition); $tree = new MenuLinkTreeElement($link, TRUE, 1, FALSE, $subtree); $manipulators = [ ['callable' => 'menu.default_tree_manipulators:checkAccess'], ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'], ]; - $tree = $this->menuTree->transform([$tree], $manipulators); - $build = $this->menuTree->build($tree); - $build['#title'] = $this->configuration['label']; - $build += [ - '#attached' => [ - 'library' => [ - 'navigation/internal.user-block', - ], - ], - '#attributes' => [ - 'data-user-block' => TRUE, - ], - ]; + $tree = $menu_tree->transform([$tree], $manipulators); + $build = $menu_tree->build($tree); + $build['#title'] = $label; + $build['#cache']['contexts'][] = 'user'; + $cacheable_metadata = CacheableMetadata::createFromRenderArray($build); + $cacheable_metadata->addCacheableDependency($account); + $cacheable_metadata->applyTo($build); return $build; } - /** - * Custom wrapper element definition. - * - * @return array - * The menu link definition. - */ - protected function menuLinkDefinition(): array { - return [ - 'menu_name' => 'navigation-user-links', - 'route_name' => 'user.page', - 'title' => $this->t('My Account'), - 'description' => '', - 'options' => [], - 'provider' => 'navigation', - 'enabled' => '1', - ]; - - } - } diff --git a/core/modules/navigation/tests/src/Functional/NavigationShortcutsBlockTest.php b/core/modules/navigation/tests/src/Functional/NavigationShortcutsBlockTest.php index d859663d90c6d4c92fb673040301bb72b1c6d72d..93fd7df80ca49f78e1495f3773d26964db394913 100644 --- a/core/modules/navigation/tests/src/Functional/NavigationShortcutsBlockTest.php +++ b/core/modules/navigation/tests/src/Functional/NavigationShortcutsBlockTest.php @@ -41,14 +41,15 @@ public function testNavigationBlock(): void { // Ensure that without enabling the shortcuts-in-page-title-link feature // in the theme, the shortcut_list cache tag is not added to the page. - $this->drupalLogin($this->drupalCreateUser([ + $admin_user = $this->drupalCreateUser([ 'administer site configuration', 'access navigation', 'administer shortcuts', 'access shortcuts', - ])); + ]); + $this->drupalLogin($admin_user); $this->drupalGet('admin/config/system/cron'); - $expected_cache_tags = [ + $expected_cache_tags = array_merge([ 'CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:form', 'block_view', 'config:block.block.title', @@ -61,7 +62,7 @@ public function testNavigationBlock(): void { 'config:system.menu.navigation-user-links', 'http_response', 'rendered', - ]; + ], $admin_user->getCacheTags()); $this->assertCacheTags($expected_cache_tags); \Drupal::configFactory() diff --git a/core/modules/navigation/tests/src/Functional/NavigationUserBlockTest.php b/core/modules/navigation/tests/src/Functional/NavigationUserBlockTest.php index 94115bc52fe287635cf44c5b202e2afa185d7aed..ec14212edb149d3ece789312597baabbeecdb6d0 100644 --- a/core/modules/navigation/tests/src/Functional/NavigationUserBlockTest.php +++ b/core/modules/navigation/tests/src/Functional/NavigationUserBlockTest.php @@ -79,7 +79,7 @@ public function testNavigationUserBlock(): void { $this->verifyDynamicPageCache($test_page_url, 'HIT'); // We should see the users name in the navigation menu. $rendered_user_name = $this->cssSelect('[aria-controls="navigation-link-navigationuser-linksuserwrapper"] > .toolbar-button__label')[0]->getText(); - $this->assertEquals('My Account', $rendered_user_name); + $this->assertEquals($this->normalUser->getDisplayName(), $rendered_user_name); // We should see all three user links in the page. $link_labels = ['View profile', 'Edit profile', 'Log out']; @@ -97,7 +97,7 @@ public function testNavigationUserBlock(): void { $this->verifyDynamicPageCache($test_page_url, 'MISS'); $this->verifyDynamicPageCache($test_page_url, 'HIT'); $rendered_user_name = $this->cssSelect('[aria-controls="navigation-link-navigationuser-linksuserwrapper"] > .toolbar-button__label')[0]->getText(); - $this->assertEquals('My Account', $rendered_user_name); + $this->assertEquals($this->adminUser->getDisplayName(), $rendered_user_name); // The Edit profile link should link to the users edit profile page. $links = $this->getSession()->getPage()->findAll('named', ['link', 'Edit profile']); $this->assertStringContainsString('/user/edit', $links[0]->getAttribute('href')); @@ -123,7 +123,7 @@ public function testNavigationUserBlockFallback(): void { $this->drupalLogin($this->normalUser); // We should see the users name in the navigation menu in a link. $rendered_user_name = $this->cssSelect('a.toolbar-button--icon--navigation-user-links-user-wrapper')[0]->getText(); - $this->assertEquals('My Account', $rendered_user_name); + $this->assertEquals($this->normalUser->getDisplayName(), $rendered_user_name); } } diff --git a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php index 9874723b82703cbfb01075be5eb4383b591fd1bd..974d9ddd05aaf690efed49cc17d5d44dccf6bb0a 100644 --- a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php +++ b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php @@ -89,7 +89,7 @@ public function testLogin(): void { ], 'CacheDeleteCount' => 0, 'CacheTagChecksumCount' => 3, - 'CacheTagIsValidCount' => 29, + 'CacheTagIsValidCount' => 30, 'CacheTagInvalidationCount' => 0, 'ScriptCount' => 2, 'ScriptBytes' => 215500,