diff --git a/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php b/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php index 12049f55c6..5b299ecaa1 100644 --- a/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php +++ b/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php @@ -83,7 +83,7 @@ public function form(array $form, FormStateInterface $form_state) { // @todo Expand to work for all view modes in // https://www.drupal.org/node/2907413. - if ($this->entity->getMode() === 'default') { + if ($this->isCanonicalMode($this->entity->getMode())) { $entity_type = $this->entityTypeManager->getDefinition($this->entity->getTargetEntityTypeId()); $form['layout']['allow_custom'] = [ '#type' => 'checkbox', @@ -113,9 +113,45 @@ public function form(array $form, FormStateInterface $form_state) { unset($form['#entity_builders']['layout_builder']); } } + // For non-canonical modes, the existing value should be preserved. + else { + $form['layout']['allow_custom'] = [ + '#type' => 'value', + '#value' => $this->entity->isOverridable(), + ]; + } return $form; } + /** + * Determines if the mode is used by the canonical route. + * + * @param string $mode + * The view mode. + * + * @return bool + * TRUE if the mode is valid, FALSE otherwise. + */ + protected function isCanonicalMode($mode) { + // @todo This is a convention core uses but is not a given, nor is it easily + // introspectable. Address in https://www.drupal.org/node/2907413. + $canonical_mode = 'full'; + + if ($mode === $canonical_mode) { + return TRUE; + } + + // The default mode is valid if the canonical mode is not enabled. + if ($mode === 'default') { + $query = $this->entityTypeManager->getStorage($this->entity->getEntityTypeId())->getQuery() + ->condition('status', TRUE) + ->condition('mode', $canonical_mode); + return !$query->count()->execute(); + } + + return FALSE; + } + /** * Determines if the defaults have any overrides. * diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php index 5629dc9982..d54180978b 100644 --- a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php +++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php @@ -580,6 +580,12 @@ public function testLayoutBuilderUiFullViewMode() { ])); $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field'; + + // For the purposes of this test, turn the full view mode on and off to + // prevent copying from the customized default view mode. + $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => TRUE], 'Save'); + $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => FALSE], 'Save'); + // Allow overrides for the layout. $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save'); $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save'); @@ -597,14 +603,17 @@ public function testLayoutBuilderUiFullViewMode() { // The default view mode is used for both the node display and layout UI. $this->drupalGet('node/1'); $assert_session->pageTextContains('This is the default view mode'); + $assert_session->pageTextNotContains('This is the full view mode'); $this->drupalGet('node/1/layout'); $assert_session->pageTextContains('This is the default view mode'); + $assert_session->pageTextNotContains('This is the full view mode'); $page->pressButton('Discard changes'); $page->pressButton('Confirm'); // Enable the full view mode and customize it. $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => TRUE], 'Save'); $this->drupalPostForm("$field_ui_prefix/display/full", ['layout[enabled]' => TRUE], 'Save'); + $this->drupalPostForm("$field_ui_prefix/display/full", ['layout[allow_custom]' => TRUE], 'Save'); $this->drupalGet("$field_ui_prefix/display/full/layout"); $this->clickLink('Add Block'); $this->clickLink('Powered by Drupal'); @@ -617,8 +626,10 @@ public function testLayoutBuilderUiFullViewMode() { // The full view mode is now used for both the node display and layout UI. $this->drupalGet('node/1'); $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); $this->drupalGet('node/1/layout'); $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); $page->pressButton('Discard changes'); $page->pressButton('Confirm'); @@ -626,8 +637,97 @@ public function testLayoutBuilderUiFullViewMode() { $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => FALSE], 'Save'); $this->drupalGet('node/1'); $assert_session->pageTextContains('This is the default view mode'); + $assert_session->pageTextNotContains('This is the full view mode'); $this->drupalGet('node/1/layout'); $assert_session->pageTextContains('This is the default view mode'); + $assert_session->pageTextNotContains('This is the full view mode'); + $page->pressButton('Discard changes'); + $page->pressButton('Confirm'); + + // Re-enabling the full view mode restores the layout changes. + $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => TRUE], 'Save'); + $this->drupalGet('node/1'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + $this->drupalGet('node/1/layout'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + + // Create an override of the full view mode. + $this->clickLink('Add Block'); + $this->clickLink('Powered by Drupal'); + $page->fillField('settings[label]', 'This is an override of the full view mode'); + $page->checkField('settings[label_display]'); + $page->pressButton('Add Block'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $page->pressButton('Save layout'); + + $this->drupalGet('node/1'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + $this->drupalGet('node/1/layout'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + $page->pressButton('Discard changes'); + $page->pressButton('Confirm'); + + // The override does not affect the full view mode. + $this->drupalGet("$field_ui_prefix/display/full/layout"); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + + // Reverting the override restores back to the full view mode. + $this->drupalGet('node/1/layout'); + $page->pressButton('Revert to default'); + $page->pressButton('Revert'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + $this->drupalGet('node/1/layout'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextNotContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + + // Recreate an override of the full view mode. + $this->clickLink('Add Block'); + $this->clickLink('Powered by Drupal'); + $page->fillField('settings[label]', 'This is an override of the full view mode'); + $page->checkField('settings[label_display]'); + $page->pressButton('Add Block'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $page->pressButton('Save layout'); + + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + $this->drupalGet('node/1/layout'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + $page->pressButton('Discard changes'); + $page->pressButton('Confirm'); + + // Disable the full view mode. + $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => FALSE], 'Save'); + + // The override of the full view mode is still available. + $this->drupalGet('node/1'); + $assert_session->pageTextContains('This is the full view mode'); + $assert_session->pageTextContains('This is an override of the full view mode'); + $assert_session->pageTextNotContains('This is the default view mode'); + + // Reverting the override restores back to the default view mode. + $this->drupalGet('node/1/layout'); + $page->pressButton('Revert to default'); + $page->pressButton('Revert'); + $assert_session->pageTextContains('This is the default view mode'); + $assert_session->pageTextNotContains('This is the full view mode'); + $this->drupalGet('node/1/layout'); + $assert_session->pageTextContains('This is the default view mode'); + $assert_session->pageTextNotContains('This is the full view mode'); $page->pressButton('Discard changes'); $page->pressButton('Confirm'); }