From aeac2967ce9a31345f481fd41050517d3be954d2 Mon Sep 17 00:00:00 2001 From: Lauri Eskola <lauri.eskola@acquia.com> Date: Fri, 3 Feb 2023 19:13:45 +0200 Subject: [PATCH] =?UTF-8?q?Issue=20#2632750=20by=20Wim=20Leers,=20bnjmnm,?= =?UTF-8?q?=20krlucas,=20ronaldtebrake,=20zaporylie,=20mherchel,=20Fabianx?= =?UTF-8?q?,=20webchick,=20yogeshchaugule8,=20catch,=20darol100,=20yoroy,?= =?UTF-8?q?=20Bojhan,=20G=C3=A1bor=20Hojtsy:=20Interface=20previews/skelet?= =?UTF-8?q?on=20screens=20through=20optional=20"preview"=20or=20"placehold?= =?UTF-8?q?er"=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Render/PlaceholderGenerator.php | 4 + core/lib/Drupal/Core/Render/Renderer.php | 1 + core/modules/big_pipe/big_pipe.module | 54 ++++++++++++ core/modules/big_pipe/src/Render/BigPipe.php | 11 +-- .../Render/Placeholder/BigPipeStrategy.php | 17 +++- .../big-pipe-interface-preview.html.twig | 9 ++ .../big_pipe_bypass_js.info.yml | 5 ++ .../big_pipe_bypass_js.module | 17 ++++ .../big_pipe_test/big_pipe_test.routing.yml | 8 ++ .../src/BigPipePlaceholderTestCases.php | 29 +++++- .../src/BigPipeTestController.php | 31 +++++++ .../tests/src/Functional/BigPipeTest.php | 2 +- .../BigPipePreviewTest.php | 63 +++++++++++++ ...peInterfacePreviewThemeSuggestionsTest.php | 88 +++++++++++++++++++ ...r-link-builder-renderDisplayName.html.twig | 1 + .../umami/js/components/messages/messages.js | 49 +++++++++++ .../demo_umami/themes/umami/umami.info.yml | 3 +- .../themes/umami/umami.libraries.yml | 4 +- .../big-pipe-interface-preview.html.twig | 9 ++ 19 files changed, 390 insertions(+), 15 deletions(-) create mode 100644 core/modules/big_pipe/templates/big-pipe-interface-preview.html.twig create mode 100644 core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.info.yml create mode 100644 core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.module create mode 100644 core/modules/big_pipe/tests/src/FunctionalJavascript/BigPipePreviewTest.php create mode 100644 core/modules/big_pipe/tests/src/Kernel/BigPipeInterfacePreviewThemeSuggestionsTest.php create mode 100644 core/modules/big_pipe/tests/themes/big_pipe_test_theme/templates/big-pipe-interface-preview--user-toolbar-link-builder-renderDisplayName.html.twig create mode 100644 core/profiles/demo_umami/themes/umami/js/components/messages/messages.js create mode 100644 core/themes/stable9/templates/content/big-pipe-interface-preview.html.twig diff --git a/core/lib/Drupal/Core/Render/PlaceholderGenerator.php b/core/lib/Drupal/Core/Render/PlaceholderGenerator.php index de50f06a4f3d..c00da6ca5321 100644 --- a/core/lib/Drupal/Core/Render/PlaceholderGenerator.php +++ b/core/lib/Drupal/Core/Render/PlaceholderGenerator.php @@ -77,6 +77,10 @@ public function createPlaceholder(array $element) { '#cache' => TRUE, ]); + if (isset($element['#lazy_builder_preview'])) { + $placeholder_render_array['#preview'] = $element['#lazy_builder_preview']; + } + // Be sure cache contexts and tags are sorted before serializing them and // making hash. Issue #3225328 removes sort from contexts and tags arrays // for performances reasons. diff --git a/core/lib/Drupal/Core/Render/Renderer.php b/core/lib/Drupal/Core/Render/Renderer.php index da19e3281f0e..8b95a5bc0f34 100644 --- a/core/lib/Drupal/Core/Render/Renderer.php +++ b/core/lib/Drupal/Core/Render/Renderer.php @@ -325,6 +325,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) { '#lazy_builder', '#cache', '#create_placeholder', + '#lazy_builder_preview', // The keys below are not actually supported, but these are added // automatically by the Renderer. Adding them as though they are // supported allows us to avoid throwing an exception 100% of the time. diff --git a/core/modules/big_pipe/big_pipe.module b/core/modules/big_pipe/big_pipe.module index fa0518ad3d1f..d7bc9e86c621 100644 --- a/core/modules/big_pipe/big_pipe.module +++ b/core/modules/big_pipe/big_pipe.module @@ -76,3 +76,57 @@ function big_pipe_page_attachments(array &$page) { } } } + +/** + * Implements hook_theme(). + */ +function big_pipe_theme() { + return [ + 'big_pipe_interface_preview' => [ + 'variables' => [ + 'callback' => NULL, + 'arguments' => NULL, + 'preview' => NULL, + ], + ], + ]; +} + +/** + * Implements hook_theme_suggestions_HOOK(). + */ +function big_pipe_theme_suggestions_big_pipe_interface_preview(array $variables) { + $common_callbacks_simplified_suggestions = [ + 'Drupal_block_BlockViewBuilder__lazyBuilder' => 'block', + ]; + + $suggestions = []; + $suggestion = 'big_pipe_interface_preview'; + if ($variables['callback']) { + $callback = preg_replace('/[^a-zA-Z0-9]/', '_', $variables['callback']); + if (is_array($callback)) { + $callback = implode('__', $callback); + } + + // Use simplified template suggestion, if any. + // For example, this simplifies + // big-pipe-interface-preview--Drupal-block-BlockViewBuilder--lazyBuilder--<BLOCK ID>.html.twig + // to + // big-pipe-interface-preview--block--<BLOCK ID>.html.twig + if (isset($common_callbacks_simplified_suggestions[$callback])) { + $callback = $common_callbacks_simplified_suggestions[$callback]; + } + + $suggestions[] = $suggestion .= '__' . $callback; + if (is_array($variables['arguments'])) { + $arguments = preg_replace('/[^a-zA-Z0-9]/', '_', $variables['arguments']); + foreach ($arguments as $argument) { + if (empty($argument)) { + continue; + } + $suggestions[] = $suggestion . '__' . $argument; + } + } + } + return $suggestions; +} diff --git a/core/modules/big_pipe/src/Render/BigPipe.php b/core/modules/big_pipe/src/Render/BigPipe.php index 985502876338..0461890b7143 100644 --- a/core/modules/big_pipe/src/Render/BigPipe.php +++ b/core/modules/big_pipe/src/Render/BigPipe.php @@ -711,14 +711,11 @@ protected function renderPlaceholder($placeholder, array $placeholder_render_arr * only keep the first occurrence. */ protected function getPlaceholderOrder($html, $placeholders) { - $fragments = explode('<span data-big-pipe-placeholder-id="', $html); - array_shift($fragments); $placeholder_ids = []; - - foreach ($fragments as $fragment) { - $t = explode('"></span>', $fragment, 2); - $placeholder_id = $t[0]; - $placeholder_ids[] = $placeholder_id; + $dom = Html::load($html); + $xpath = new \DOMXPath($dom); + foreach ($xpath->query('//span[@data-big-pipe-placeholder-id]') as $node) { + $placeholder_ids[] = Html::escape($node->getAttribute('data-big-pipe-placeholder-id')); } $placeholder_ids = array_unique($placeholder_ids); diff --git a/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php b/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php index 74a031506cdb..6219a1fddca6 100644 --- a/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php +++ b/core/modules/big_pipe/src/Render/Placeholder/BigPipeStrategy.php @@ -198,8 +198,23 @@ protected static function placeholderIsAttributeSafe($placeholder) { protected static function createBigPipeJsPlaceholder($original_placeholder, array $placeholder_render_array) { $big_pipe_placeholder_id = static::generateBigPipePlaceholderId($original_placeholder, $placeholder_render_array); + $interface_preview = []; + if (isset($placeholder_render_array['#lazy_builder'])) { + $interface_preview = [ + '#theme' => 'big_pipe_interface_preview', + '#callback' => $placeholder_render_array['#lazy_builder'][0], + '#arguments' => $placeholder_render_array['#lazy_builder'][1], + ]; + if (isset($placeholder_render_array['#preview'])) { + $interface_preview['#preview'] = $placeholder_render_array['#preview']; + unset($placeholder_render_array['#preview']); + } + } + return [ - '#markup' => '<span data-big-pipe-placeholder-id="' . Html::escape($big_pipe_placeholder_id) . '"></span>', + '#prefix' => '<span data-big-pipe-placeholder-id="' . Html::escape($big_pipe_placeholder_id) . '">', + 'interface_preview' => $interface_preview, + '#suffix' => '</span>', '#cache' => [ 'max-age' => 0, 'contexts' => [ diff --git a/core/modules/big_pipe/templates/big-pipe-interface-preview.html.twig b/core/modules/big_pipe/templates/big-pipe-interface-preview.html.twig new file mode 100644 index 000000000000..06a2d13c11bd --- /dev/null +++ b/core/modules/big_pipe/templates/big-pipe-interface-preview.html.twig @@ -0,0 +1,9 @@ +{# +/** + * @file + * Default theme implementation for a BigPipe JS placeholder interface preview. + * + * @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy::createBigPipeJsPlaceholder() + */ +#} +{{ preview }} diff --git a/core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.info.yml b/core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.info.yml new file mode 100644 index 000000000000..0278a7b5a64e --- /dev/null +++ b/core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.info.yml @@ -0,0 +1,5 @@ +name: 'BigPipe bypass JS' +type: module +description: 'Prevents the loading of Big Pipe JavaScript. Used for testing preview templates.' +package: Testing +version: VERSION diff --git a/core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.module b/core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.module new file mode 100644 index 000000000000..3cba4c13c3c8 --- /dev/null +++ b/core/modules/big_pipe/tests/modules/big_pipe_bypass_js/big_pipe_bypass_js.module @@ -0,0 +1,17 @@ +<?php + +/** + * @file + * Provides a way to bypass Big Pipe JavaScript. + */ + +/** + * Implements hook_library_info_alter(). + * + * Disables Big Pipe JavaScript by removing the js file from the library. + */ +function big_pipe_bypass_js_library_info_alter(&$libraries, $extension) { + if ($extension === 'big_pipe') { + unset($libraries['big_pipe']['js']); + } +} diff --git a/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml b/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml index 152bf7ac8951..8edbcec487b4 100644 --- a/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml +++ b/core/modules/big_pipe/tests/modules/big_pipe_test/big_pipe_test.routing.yml @@ -23,3 +23,11 @@ big_pipe_test_multi_occurrence: _title: 'BigPipe test multiple occurrences of the same placeholder' requirements: _access: 'TRUE' + +big_pipe_test_preview: + path: '/big_pipe_test_preview' + defaults: + _controller: '\Drupal\big_pipe_test\BigPipeTestController::placeholderPreview' + _title: 'Test placeholder previews' + requirements: + _access: 'TRUE' diff --git a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php index 22d1da8f1ee9..b19d01872cee 100644 --- a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php +++ b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipePlaceholderTestCases.php @@ -3,6 +3,7 @@ /** * @file */ +// cSpell:ignore Vxezb namespace Drupal\big_pipe_test; @@ -58,7 +59,13 @@ public static function cases(ContainerInterface $container = NULL, AccountInterf ); $status_messages->bigPipePlaceholderId = 'callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA'; $status_messages->bigPipePlaceholderRenderArray = [ - '#markup' => '<span data-big-pipe-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA"></span>', + '#prefix' => '<span data-big-pipe-placeholder-id="callback=Drupal%5CCore%5CRender%5CElement%5CStatusMessages%3A%3ArenderMessages&args%5B0%5D&token=_HAdUpwWmet0TOTe2PSiJuMntExoshbm1kh2wQzzzAA">', + 'interface_preview' => [ + '#theme' => 'big_pipe_interface_preview', + '#callback' => 'Drupal\Core\Render\Element\StatusMessages::renderMessages', + '#arguments' => [NULL], + ], + '#suffix' => '</span>', '#cache' => $cacheability_depends_on_session_and_nojs_cookie, '#attached' => [ 'library' => ['big_pipe/big_pipe'], @@ -199,7 +206,9 @@ public static function cases(ContainerInterface $container = NULL, AccountInterf ); $current_time->bigPipePlaceholderId = 'timecurrent-timetime'; $current_time->bigPipePlaceholderRenderArray = [ - '#markup' => '<span data-big-pipe-placeholder-id="timecurrent-timetime"></span>', + '#prefix' => '<span data-big-pipe-placeholder-id="timecurrent-timetime">', + 'interface_preview' => [], + '#suffix' => '</span>', '#cache' => $cacheability_depends_on_session_and_nojs_cookie, '#attached' => [ 'library' => ['big_pipe/big_pipe'], @@ -247,7 +256,13 @@ public static function cases(ContainerInterface $container = NULL, AccountInterf ); $exception->bigPipePlaceholderId = 'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU'; $exception->bigPipePlaceholderRenderArray = [ - '#markup' => '<span data-big-pipe-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU"></span>', + '#prefix' => '<span data-big-pipe-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3Aexception&args%5B0%5D=llamas&args%5B1%5D=suck&token=uhKFNfT4eF449_W-kDQX8E5z4yHyt0-nSHUlwaGAQeU">', + 'interface_preview' => [ + '#theme' => 'big_pipe_interface_preview', + '#callback' => '\Drupal\big_pipe_test\BigPipeTestController::exception', + '#arguments' => ['llamas', 'suck'], + ], + '#suffix' => '</span>', '#cache' => $cacheability_depends_on_session_and_nojs_cookie, '#attached' => [ 'library' => ['big_pipe/big_pipe'], @@ -289,7 +304,13 @@ public static function cases(ContainerInterface $container = NULL, AccountInterf ); $embedded_response_exception->bigPipePlaceholderId = 'callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=' . $token; $embedded_response_exception->bigPipePlaceholderRenderArray = [ - '#markup' => '<span data-big-pipe-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=' . $token . '"></span>', + '#prefix' => '<span data-big-pipe-placeholder-id="callback=%5CDrupal%5Cbig_pipe_test%5CBigPipeTestController%3A%3AresponseException&&token=PxOHfS_QL-T01NjBgu7Z7I04tIwMp6La5vM-mVxezbU">', + 'interface_preview' => [ + '#theme' => 'big_pipe_interface_preview', + '#callback' => '\Drupal\big_pipe_test\BigPipeTestController::responseException', + '#arguments' => [], + ], + '#suffix' => '</span>', '#cache' => $cacheability_depends_on_session_and_nojs_cookie, '#attached' => [ 'library' => ['big_pipe/big_pipe'], diff --git a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php index 0b36f1f8b268..6e6ea88f6a9b 100644 --- a/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php +++ b/core/modules/big_pipe/tests/modules/big_pipe_test/src/BigPipeTestController.php @@ -82,6 +82,37 @@ public function multiOccurrence() { ]; } + /** + * A page with placeholder preview. + * + * @return array[] + */ + public function placeholderPreview() { + return [ + 'user_container' => [ + '#type' => 'container', + '#attributes' => ['id' => 'placeholder-preview-twig-container'], + 'user' => [ + '#lazy_builder' => ['user.toolbar_link_builder:renderDisplayName', []], + '#create_placeholder' => TRUE, + ], + ], + 'user_links_container' => [ + '#type' => 'container', + '#attributes' => ['id' => 'placeholder-render-array-container'], + 'user_links' => [ + '#lazy_builder' => [static::class . '::helloOrYarhar', []], + '#create_placeholder' => TRUE, + '#lazy_builder_preview' => [ + '#attributes' => ['id' => 'render-array-preview'], + '#type' => 'container', + '#markup' => 'There is a lamb and there is a puppy', + ], + ], + ], + ]; + } + /** * #lazy_builder callback; builds <time> markup with current time. * diff --git a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php index 33900bdea47f..246cd47a64d9 100644 --- a/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php +++ b/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php @@ -370,7 +370,7 @@ protected function assertBigPipePlaceholders(array $expected_big_pipe_placeholde $placeholder_replacement_positions = []; foreach ($expected_big_pipe_placeholders as $big_pipe_placeholder_id => $expected_ajax_response) { // Verify expected placeholder. - $expected_placeholder_html = '<span data-big-pipe-placeholder-id="' . $big_pipe_placeholder_id . '"></span>'; + $expected_placeholder_html = '<span data-big-pipe-placeholder-id="' . $big_pipe_placeholder_id . '">'; $this->assertSession()->responseContains($expected_placeholder_html); $pos = strpos($this->getSession()->getPage()->getContent(), $expected_placeholder_html); $placeholder_positions[$pos] = $big_pipe_placeholder_id; diff --git a/core/modules/big_pipe/tests/src/FunctionalJavascript/BigPipePreviewTest.php b/core/modules/big_pipe/tests/src/FunctionalJavascript/BigPipePreviewTest.php new file mode 100644 index 000000000000..1ff07ecbd1f7 --- /dev/null +++ b/core/modules/big_pipe/tests/src/FunctionalJavascript/BigPipePreviewTest.php @@ -0,0 +1,63 @@ +<?php + +namespace Drupal\Tests\big_pipe\FunctionalJavascript; + +use Drupal\FunctionalJavascriptTests\WebDriverTestBase; + +/** + * Tests placeholder preview functionality. + * + * @group big_pipe + */ +class BigPipePreviewTest extends WebDriverTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'big_pipe', + 'user', + 'big_pipe_bypass_js', + 'big_pipe_test', + ]; + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'big_pipe_test_theme'; + + /** + * Test preview functionality within placeholders. + */ + public function testLazyLoaderPreview() { + $user = $this->drupalCreateUser([]); + $display_name = $user->getDisplayName(); + $this->drupalLogin($user); + + $this->drupalGet('big_pipe_test_preview'); + + // This test begins with the big_pipe_bypass_js module enabled, which blocks + // Big Pipe's JavaScript from loading. Without that JavaScript, the + // placeholder and previews are not replaced and we can reliably test their + // presence. + $this->assertSession()->elementExists('css', '#placeholder-preview-twig-container [data-big-pipe-placeholder-id] > .i-am-taking-up-space'); + $this->assertSession()->elementTextEquals('css', '#placeholder-preview-twig-container [data-big-pipe-placeholder-id] > .i-am-taking-up-space', 'LOOK AT ME I AM CONSUMING SPACE FOR LATER'); + $this->assertSession()->elementTextNotContains('css', '#placeholder-preview-twig-container', $display_name); + + $this->assertSession()->pageTextContains('There is a lamb and there is a puppy'); + $this->assertSession()->elementTextEquals('css', '#placeholder-render-array-container [data-big-pipe-placeholder-id] > #render-array-preview', 'There is a lamb and there is a puppy'); + $this->assertSession()->elementTextNotContains('css', '#placeholder-render-array-container', 'Yarhar llamas forever!'); + + // Uninstall big_pipe_bypass_js. + \Drupal::service('module_installer')->uninstall(['big_pipe_bypass_js']); + $this->rebuildAll(); + $this->drupalGet('big_pipe_test_preview'); + $this->assertSession()->waitForElementRemoved('css', '[data-big-pipe-placeholder-id]', 20000); + $this->assertSession()->elementTextContains('css', '#placeholder-preview-twig-container', $display_name); + $this->assertSession()->pageTextNotContains('LOOK AT ME I AM CONSUMING SPACE FOR LATER'); + + $this->assertSession()->elementTextContains('css', '#placeholder-render-array-container marquee', 'Yarhar llamas forever!'); + $this->assertSession()->pageTextNotContains('There is a lamb and there is a puppy'); + } + +} diff --git a/core/modules/big_pipe/tests/src/Kernel/BigPipeInterfacePreviewThemeSuggestionsTest.php b/core/modules/big_pipe/tests/src/Kernel/BigPipeInterfacePreviewThemeSuggestionsTest.php new file mode 100644 index 000000000000..9064a6074a23 --- /dev/null +++ b/core/modules/big_pipe/tests/src/Kernel/BigPipeInterfacePreviewThemeSuggestionsTest.php @@ -0,0 +1,88 @@ +<?php + +namespace Drupal\Tests\big_pipe\Kernel; + +use Drupal\KernelTests\KernelTestBase; +use Drupal\block\Entity\Block; + +/** + * Tests the big_pipe_theme_suggestions_big_pipe_interface_preview() function. + * + * @group big_pipe + */ +class BigPipeInterfacePreviewThemeSuggestionsTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = ['block', 'big_pipe', 'system']; + + /** + * The block being tested. + * + * @var \Drupal\block\Entity\BlockInterface + */ + protected $block; + + /** + * The block storage. + * + * @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface + */ + protected $controller; + + /** + * The block view builder. + * + * @var \Drupal\block\BlockViewBuilder + */ + protected $blockViewBuilder; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->controller = $this->container + ->get('entity_type.manager') + ->getStorage('block'); + + $this->blockViewBuilder = $this->container + ->get('entity_type.manager') + ->getViewBuilder('block'); + } + + /** + * Tests template suggestions from big_pipe_theme_suggestions_big_pipe_interface_preview(). + */ + public function testBigPipeThemeHookSuggestions() { + $entity = $this->controller->create([ + 'id' => 'test_block1', + 'theme' => 'stark', + 'plugin' => 'test_html', + ]); + $entity->save(); + + // Test the rendering of a block. + $block = Block::load('test_block1'); + // Using the BlockViewBuilder we will be able to get a lovely + // #lazy_builder callback assigned. + $build = $this->blockViewBuilder->view($block); + + $variables = []; + // In turn this is what createBigPipeJsPlaceholder() uses to + // build the BigPipe JS placeholder render array which is used as input + // for big_pipe_theme_suggestions_big_pipe_interface_preview(). + $variables['callback'] = $build['#lazy_builder'][0]; + $variables['arguments'] = $build['#lazy_builder'][1]; + $suggestions = big_pipe_theme_suggestions_big_pipe_interface_preview($variables); + $suggested_id = preg_replace('/[^a-zA-Z0-9]/', '_', $block->id()); + $this->assertSame([ + 'big_pipe_interface_preview__block', + 'big_pipe_interface_preview__block__' . $suggested_id, + 'big_pipe_interface_preview__block__full', + ], $suggestions); + } + +} diff --git a/core/modules/big_pipe/tests/themes/big_pipe_test_theme/templates/big-pipe-interface-preview--user-toolbar-link-builder-renderDisplayName.html.twig b/core/modules/big_pipe/tests/themes/big_pipe_test_theme/templates/big-pipe-interface-preview--user-toolbar-link-builder-renderDisplayName.html.twig new file mode 100644 index 000000000000..22b185a88d85 --- /dev/null +++ b/core/modules/big_pipe/tests/themes/big_pipe_test_theme/templates/big-pipe-interface-preview--user-toolbar-link-builder-renderDisplayName.html.twig @@ -0,0 +1 @@ +<span class="i-am-taking-up-space">LOOK AT ME I AM CONSUMING SPACE FOR LATER</span> diff --git a/core/profiles/demo_umami/themes/umami/js/components/messages/messages.js b/core/profiles/demo_umami/themes/umami/js/components/messages/messages.js new file mode 100644 index 000000000000..6f56fd345427 --- /dev/null +++ b/core/profiles/demo_umami/themes/umami/js/components/messages/messages.js @@ -0,0 +1,49 @@ +/** + * @file + * Message template overrides. + */ + +((Drupal) => { + /** + * Overrides message theme function. + * + * @param {object} message + * The message object. + * @param {string} message.text + * The message text. + * @param {object} options + * The message context. + * @param {string} options.type + * The message type. + * @param {string} options.id + * ID of the message, for reference. + * + * @return {HTMLElement} + * A DOM Node. + */ + Drupal.theme.message = ({ text }, { type, id }) => { + const messagesTypes = Drupal.Message.getMessageTypeLabels(); + const messageWrapper = document.createElement('div'); + + messageWrapper.setAttribute('class', `messages messages--${type}`); + messageWrapper.setAttribute( + 'role', + type === 'error' || type === 'warning' ? 'alert' : 'status', + ); + messageWrapper.setAttribute('data-drupal-message-id', id); + messageWrapper.setAttribute('data-drupal-message-type', type); + + messageWrapper.innerHTML = ` + <div class="messages__content container"> + <h2 class="visually-hidden"> + ${messagesTypes[type]} + </h2> + <span class="messages__item"> + ${text} + </span> + </div> + `; + + return messageWrapper; + }; +})(Drupal); diff --git a/core/profiles/demo_umami/themes/umami/umami.info.yml b/core/profiles/demo_umami/themes/umami/umami.info.yml index 35fe076ff522..1e615dea31ab 100644 --- a/core/profiles/demo_umami/themes/umami/umami.info.yml +++ b/core/profiles/demo_umami/themes/umami/umami.info.yml @@ -7,7 +7,6 @@ libraries: - umami/classy.base - core/normalize - umami/global - - umami/messages libraries-override: layout_builder/twocol_section: @@ -24,6 +23,8 @@ libraries-override: layouts/fourcol_section/fourcol_section.css: layouts/fourcol_section/fourcol_section.css libraries-extend: + core/drupal.message: + - umami/messages tour/tour-styling: - umami/demo-umami-tour core/drupal.dialog: diff --git a/core/profiles/demo_umami/themes/umami/umami.libraries.yml b/core/profiles/demo_umami/themes/umami/umami.libraries.yml index db84ec743d97..934d3f5e8258 100644 --- a/core/profiles/demo_umami/themes/umami/umami.libraries.yml +++ b/core/profiles/demo_umami/themes/umami/umami.libraries.yml @@ -56,7 +56,9 @@ global: messages: css: component: - css/components/messages/messages.css: { weight: -10 } + css/components/messages/messages.css: {} + js: + js/components/messages/messages.js: {} more-link: css: diff --git a/core/themes/stable9/templates/content/big-pipe-interface-preview.html.twig b/core/themes/stable9/templates/content/big-pipe-interface-preview.html.twig new file mode 100644 index 000000000000..edafd6ef8d74 --- /dev/null +++ b/core/themes/stable9/templates/content/big-pipe-interface-preview.html.twig @@ -0,0 +1,9 @@ +{# +/** + * @file + * Theme override for a BigPipe JS placeholder interface preview. + * + * @see \Drupal\big_pipe\Render\Placeholder\BigPipeStrategy::createBigPipeJsPlaceholder() + */ +#} +{{ preview }} -- GitLab