diff --git a/core/modules/layout_builder/css/layout-builder.css b/core/modules/layout_builder/css/layout-builder.css index d4c48248de..b9eb7d1dc0 100644 --- a/core/modules/layout_builder/css/layout-builder.css +++ b/core/modules/layout_builder/css/layout-builder.css @@ -104,6 +104,10 @@ border-bottom: 2px dashed #979797; } +.layout-builder-block-hidden { + background-color: #f7f7f7; +} + /* * Layout Builder messages. */ @@ -122,7 +126,8 @@ /* Label when "content preview" is disabled. */ -.layout-builder-block__content-preview-placeholder-label { +.layout-builder-block__content-preview-placeholder-label, +.layout-builder-block-hidden { margin: 0; text-align: center; font-size: 1.429em; diff --git a/core/modules/layout_builder/css/layout-builder.pcss.css b/core/modules/layout_builder/css/layout-builder.pcss.css index 7ddb9543e0..8cd9e03a8b 100644 --- a/core/modules/layout_builder/css/layout-builder.pcss.css +++ b/core/modules/layout_builder/css/layout-builder.pcss.css @@ -3,6 +3,10 @@ * Layout Builder UI styling. */ +.layout-builder-block-hidden { + background-color: #f7f7f7; +} + .layout-builder { padding: 1.5em 1.5em 0.5em; border: 3px solid #2f91da; @@ -111,7 +115,8 @@ } /* Label when "content preview" is disabled. */ -.layout-builder-block__content-preview-placeholder-label { +.layout-builder-block__content-preview-placeholder-label, +.layout-builder-block-hidden { margin: 0; text-align: center; font-size: 1.429em; diff --git a/core/modules/layout_builder/layout_builder.links.contextual.yml b/core/modules/layout_builder/layout_builder.links.contextual.yml index 4bbfcc9e64..4979b506a1 100644 --- a/core/modules/layout_builder/layout_builder.links.contextual.yml +++ b/core/modules/layout_builder/layout_builder.links.contextual.yml @@ -27,3 +27,11 @@ layout_builder_block_remove: class: ['use-ajax'] data-dialog-type: dialog data-dialog-renderer: off_canvas + +layout_builder_block_hide: + title: 'Toggle hidden' + route_name: 'layout_builder.hide_block' + group: 'layout_builder_block' + options: + attributes: + class: ['use-ajax'] diff --git a/core/modules/layout_builder/layout_builder.routing.yml b/core/modules/layout_builder/layout_builder.routing.yml index fa72dcec93..3bad71e1d7 100644 --- a/core/modules/layout_builder/layout_builder.routing.yml +++ b/core/modules/layout_builder/layout_builder.routing.yml @@ -145,3 +145,15 @@ layout_builder.move_block: parameters: section_storage: layout_builder_tempstore: TRUE + +layout_builder.hide_block: + path: '/layout_builder/hide/block/{section_storage_type}/{section_storage}/{delta}/{region}/{uuid}' + defaults: + _controller: '\Drupal\layout_builder\Controller\HideBlockController::build' + requirements: + _layout_builder_access: 'view' + options: + _admin_route: TRUE + parameters: + section_storage: + layout_builder_tempstore: TRUE diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml index 65c9365220..af06de37ca 100644 --- a/core/modules/layout_builder/layout_builder.services.yml +++ b/core/modules/layout_builder/layout_builder.services.yml @@ -50,6 +50,10 @@ services: layout_builder.render_block_component_subscriber: class: Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray arguments: ['@current_user'] + layout_builder.section_component_hidden_subscriber: + class: Drupal\layout_builder\EventSubscriber\SectionComponentHidden + tags: + - { name: event_subscriber } logger.channel.layout_builder: parent: logger.channel_base arguments: ['layout_builder'] diff --git a/core/modules/layout_builder/src/Controller/HideBlockController.php b/core/modules/layout_builder/src/Controller/HideBlockController.php new file mode 100644 index 0000000000..e758fc694c --- /dev/null +++ b/core/modules/layout_builder/src/Controller/HideBlockController.php @@ -0,0 +1,68 @@ +layoutTempstoreRepository = $layout_tempstore_repository; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('layout_builder.tempstore_repository') + ); + } + + /** + * Shows or hides a component. + * + * @param \Drupal\layout_builder\SectionStorageInterface $section_storage + * The section storage. + * @param $delta + * The section delta. + * @param $region + * The component region. + * @param $uuid + * The component uuid. + * + * @return \Drupal\Core\Ajax\AjaxResponse + */ + public function build(SectionStorageInterface $section_storage, $delta, $region, $uuid) { + $section = $section_storage->getSection($delta); + $component = $section->getComponent($uuid); + + $hidden = $component->get('hidden') ?: FALSE; + $component->set('hidden', !$hidden); + + $this->layoutTempstoreRepository->set($section_storage); + return $this->rebuildLayout($section_storage); + } + +} \ No newline at end of file diff --git a/core/modules/layout_builder/src/EventSubscriber/SectionComponentHidden.php b/core/modules/layout_builder/src/EventSubscriber/SectionComponentHidden.php new file mode 100644 index 0000000000..bfe017e56d --- /dev/null +++ b/core/modules/layout_builder/src/EventSubscriber/SectionComponentHidden.php @@ -0,0 +1,70 @@ +getComponent()->get('hidden') ?: FALSE; + if (!$hidden) { + return; + } + + if ($event->inPreview()) { + $block = $event->getPlugin(); + if (!$block instanceof BlockPluginInterface) { + return; + } + + $content = [ + '#markup' => $this->t('The "@block" block is hidden', ['@block' => $block->label()]), + ]; + + $build = [ + '#theme' => 'block', + '#configuration' => array_merge($block->getConfiguration(), ['label_display' => FALSE]), + '#plugin_id' => $block->getPluginId(), + '#base_plugin_id' => $block->getBaseId(), + '#derivative_plugin_id' => $block->getDerivativeId(), + '#weight' => $event->getComponent()->getWeight(), + '#attributes' => [ + 'class' => ['layout-builder-block-hidden'], + ], + 'content' => $content, + ]; + + $event->setBuild($build); + } + + $event->stopPropagation(); + } + +} \ No newline at end of file diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php index 5a11de6bdb..ca5912cdd1 100644 --- a/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php +++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/LayoutBuilderUiTest.php @@ -304,4 +304,58 @@ private function assertHighlightNotExists(): void { $assert_session->assertNoElementAfterWait('css', '.is-layout-builder-highlighted'); } + + /** + * Tests for hide block functionality. + */ + public function testHideBlock() { + // Enable layout builder for each content. + $this->drupalGet(static::FIELD_UI_PREFIX . '/display/default'); + $this->submitForm(['layout[allow_custom]' => TRUE], 'Save'); + + $this->createNode([ + 'type' => 'bundle_with_section_field', + ]); + + $page = $this->getSession()->getPage(); + $assert_session = $this->assertSession(); + + $this->drupalGet('node/1/layout'); + + $page->clickLink('Add section'); + $assert_session->waitForElementVisible('named', ['link', 'One column']); + $assert_session->pageTextNotContains('You have unsaved changes.'); + $page->clickLink('One column'); + $assert_session->waitForElementVisible('named', ['button', 'Add section']); + $page->pressButton('Add section'); + $assert_session->assertWaitOnAjaxRequest(); + + $page->clickLink('Add block'); + $this->assertNotEmpty($assert_session->waitForElementVisible('css', 'a:contains("Recent content")')); + $assert_session->assertWaitOnAjaxRequest(); + $page->clickLink('Recent content'); + $this->assertNotEmpty($assert_session->waitForElementVisible('css', '#drupal-off-canvas input[value="Add block"]')); + $page->pressButton('Add block'); + $assert_session->assertWaitOnAjaxRequest(); + + // Test "Hide block" functionality. + $this->clickContextualLink('.block-views-blockcontent-recent-block-1', 'Toggle hidden'); + $assert_session->assertWaitOnAjaxRequest(); + $assert_session->pageTextContains('The "Recent content" block is hidden'); + $page->pressButton('Save layout'); + $assert_session->pageTextNotContains('You have unsaved changes.'); + $this->drupalGet('node/1'); + $assert_session->pageTextNotContains('Recent content'); + + // Test "Show block" functionality. + $this->drupalGet('node/1/layout'); + $this->clickContextualLink('.block-views-blockcontent-recent-block-1', 'Toggle hidden'); + $assert_session->assertWaitOnAjaxRequest(); + $assert_session->pageTextNotContains('The "Recent content" block is hidden'); + $page->pressButton('Save layout'); + $assert_session->pageTextNotContains('You have unsaved changes.'); + $this->drupalGet('node/1'); + $assert_session->pageTextContains('Recent content'); + } + }