diff --git a/core/modules/settings_tray/settings_tray.module b/core/modules/settings_tray/settings_tray.module index 48b08caaab..2bcd445d58 100644 --- a/core/modules/settings_tray/settings_tray.module +++ b/core/modules/settings_tray/settings_tray.module @@ -11,6 +11,8 @@ use Drupal\settings_tray\Block\BlockEntityOffCanvasForm; use Drupal\settings_tray\Form\SystemBrandingOffCanvasForm; use Drupal\settings_tray\Form\SystemMenuOffCanvasForm; +use Drupal\block\BlockInterface; +use Drupal\block\Entity\Block; /** * Implements hook_help(). @@ -54,6 +56,21 @@ function settings_tray_contextual_links_view_alter(&$element, $items) { } } +/** + * Checks if a block or related configuration has overrides. + * + * @param \Drupal\block\BlockInterface $block + * The block to check for overrides. + * + * @return bool + * TRUE if the block has overrides otherwise FALSE. + * + * @internal + */ +function _settings_tray_has_block_related_overrides(BlockInterface $block) { + return \Drupal::config($block->getEntityType()->getConfigPrefix() . '.' . $block->id())->hasOverrides(); +} + /** * Implements hook_block_view_alter(). */ @@ -93,10 +110,14 @@ function settings_tray_preprocess_block(&$variables) { $block_plugin_manager = \Drupal::service('plugin.manager.block'); /** @var \Drupal\Core\Block\BlockPluginInterface $block_plugin */ $block_plugin = $block_plugin_manager->createInstance($variables['plugin_id']); - if ($access_checker->accessBlockPlugin($block_plugin)->isAllowed()) { - // Add class and attributes to all blocks to allow Javascript to target. - $variables['attributes']['class'][] = 'settings-tray-editable'; - $variables['attributes']['data-drupal-settingstray'] = 'editable'; + if (isset($variables['elements']['#contextual_links']['block']['route_parameters']['block'])) { + $block_id = $variables['elements']['#contextual_links']['block']['route_parameters']['block']; + $block = Block::load($block_id); + if ($access_checker->accessBlockPlugin($block_plugin)->isAllowed() && !_settings_tray_has_block_related_overrides($block)) { + // Add class and attributes to all blocks to allow Javascript to target. + $variables['attributes']['class'][] = 'settings-tray-editable'; + $variables['attributes']['data-drupal-settingstray'] = 'editable'; + } } } @@ -196,3 +217,15 @@ function settings_tray_css_alter(&$css, AttachedAssetsInterface $assets) { $css[$path]['group'] = 200; } } + +/** + * Implements hook_contextual_links_alter(). + */ +function settings_tray_contextual_links_alter(array &$links, $group, array $route_parameters) { + if (isset($links['settings_tray.block_configure']['route_parameters']['block'])) { + $block = Block::load($links['settings_tray.block_configure']['route_parameters']['block']); + if (_settings_tray_has_block_related_overrides($block)) { + unset($links['settings_tray.block_configure']); + } + } +} diff --git a/core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php b/core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php index 0b4290e2fa..6c40c3d5d3 100644 --- a/core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php +++ b/core/modules/settings_tray/src/Form/SystemBrandingOffCanvasForm.php @@ -56,30 +56,32 @@ public static function create(ContainerInterface $container) { public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $form = $this->plugin->buildConfigurationForm($form, $form_state); - $form['block_branding']['#type'] = 'details'; - $form['block_branding']['#weight'] = 10; - - // Unset links to Site Information form, we can make these changes here. - unset($form['block_branding']['use_site_name']['#description'], $form['block_branding']['use_site_slogan']['#description']); - - $site_config = $this->configFactory->getEditable('system.site'); - $form['site_information'] = [ - '#type' => 'details', - '#title' => t('Site details'), - '#open' => TRUE, - ]; - $form['site_information']['site_name'] = [ - '#type' => 'textfield', - '#title' => t('Site name'), - '#default_value' => $site_config->get('name'), - '#required' => TRUE, - ]; - $form['site_information']['site_slogan'] = [ - '#type' => 'textfield', - '#title' => t('Slogan'), - '#default_value' => $site_config->get('slogan'), - '#description' => t("How this is used depends on your site's theme."), - ]; + if (!$this->isSiteInfoOverridden()) { + $form['block_branding']['#type'] = 'details'; + $form['block_branding']['#weight'] = 10; + + // Unset links to Site Information form, we can make these changes here. + unset($form['block_branding']['use_site_name']['#description'], $form['block_branding']['use_site_slogan']['#description']); + + $site_config = $this->configFactory->getEditable('system.site'); + $form['site_information'] = [ + '#type' => 'details', + '#title' => t('Site details'), + '#open' => TRUE, + ]; + $form['site_information']['site_name'] = [ + '#type' => 'textfield', + '#title' => t('Site name'), + '#default_value' => $site_config->get('name'), + '#required' => TRUE, + ]; + $form['site_information']['site_slogan'] = [ + '#type' => 'textfield', + '#title' => t('Slogan'), + '#default_value' => $site_config->get('slogan'), + '#description' => t("How this is used depends on your site's theme."), + ]; + } return $form; } @@ -95,12 +97,26 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form * {@inheritdoc} */ public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { - $site_info = $form_state->getValue('site_information'); - $this->configFactory->getEditable('system.site') - ->set('name', $site_info['site_name']) - ->set('slogan', $site_info['site_slogan']) - ->save(); + if (!$this->isSiteInfoOverridden() && $form_state->hasValue('site_information')) { + $site_info = $form_state->getValue('site_information'); + + $this->configFactory->getEditable('system.site') + ->set('name', $site_info['site_name']) + ->set('slogan', $site_info['site_slogan']) + ->save(); + } + $this->plugin->submitConfigurationForm($form, $form_state); } + /** + * Determines if the site information used on this form is overridden. + * + * @return bool + * TRUE if the site name or slogan is currently overridden, otherwise FALSE. + */ + protected function isSiteInfoOverridden() { + $config = $this->configFactory->get('system.site'); + return $config->hasOverrides('name') || $config->hasOverrides('slogan'); + } } diff --git a/core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php b/core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php index 15d19a87f9..36764be9bc 100644 --- a/core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php +++ b/core/modules/settings_tray/src/Form/SystemMenuOffCanvasForm.php @@ -80,32 +80,34 @@ public static function create(ContainerInterface $container) { */ public function buildConfigurationForm(array $form, FormStateInterface $form_state) { $form = $this->plugin->buildConfigurationForm([], $form_state); - // Move the menu levels section to the bottom. - $form['menu_levels']['#weight'] = 100; - - $form['entity_form'] = [ - '#type' => 'details', - '#title' => $this->t('Edit menu %label', ['%label' => $this->menu->label()]), - '#open' => TRUE, - ]; - $form['entity_form'] += $this->getEntityForm($this->menu)->buildForm([], $form_state); - - // Print the menu link titles as text instead of a link. - if (!empty($form['entity_form']['links']['links'])) { - foreach (Element::children($form['entity_form']['links']['links']) as $child) { - $title = $form['entity_form']['links']['links'][$child]['title'][1]['#title']; - $form['entity_form']['links']['links'][$child]['title'][1] = ['#markup' => $title]; + if (!$this->isMenuOverridden()) { + // Move the menu levels section to the bottom. + $form['menu_levels']['#weight'] = 100; + + $form['entity_form'] = [ + '#type' => 'details', + '#title' => $this->t('Edit menu %label', ['%label' => $this->menu->label()]), + '#open' => TRUE, + ]; + $form['entity_form'] += $this->getEntityForm($this->menu)->buildForm([], $form_state); + + // Print the menu link titles as text instead of a link. + if (!empty($form['entity_form']['links']['links'])) { + foreach (Element::children($form['entity_form']['links']['links']) as $child) { + $title = $form['entity_form']['links']['links'][$child]['title'][1]['#title']; + $form['entity_form']['links']['links'][$child]['title'][1] = ['#markup' => $title]; + } } + // Change the header text. + $form['entity_form']['links']['links']['#header'][0] = $this->t('Link'); + $form['entity_form']['links']['links']['#header'][1]['data'] = $this->t('On'); + + // Remove the label, ID, description, and buttons from the entity form. + unset($form['entity_form']['label'], $form['entity_form']['id'], $form['entity_form']['description'], $form['entity_form']['actions']); + // Since the overview form is further nested than expected, update the + // #parents. See \Drupal\menu_ui\MenuForm::form(). + $form_state->set('menu_overview_form_parents', ['settings', 'entity_form', 'links']); } - // Change the header text. - $form['entity_form']['links']['links']['#header'][0] = $this->t('Link'); - $form['entity_form']['links']['links']['#header'][1]['data'] = $this->t('On'); - - // Remove the label, ID, description, and buttons from the entity form. - unset($form['entity_form']['label'], $form['entity_form']['id'], $form['entity_form']['description'], $form['entity_form']['actions']); - // Since the overview form is further nested than expected, update the - // #parents. See \Drupal\menu_ui\MenuForm::form(). - $form_state->set('menu_overview_form_parents', ['settings', 'entity_form', 'links']); return $form; } @@ -115,7 +117,10 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta */ public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { $this->plugin->validateConfigurationForm($form, $form_state); - $this->getEntityForm($this->menu)->validateForm($form, $form_state); + if (!$this->isMenuOverridden() && $form_state->hasValue('entity_form')) { + $this->getEntityForm($this->menu)->validateForm($form, $form_state); + } + } /** @@ -123,8 +128,11 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form */ public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { $this->plugin->submitConfigurationForm($form, $form_state); - $this->getEntityForm($this->menu)->submitForm($form, $form_state); - $this->menu->save(); + if (!$this->isMenuOverridden() && $form_state->hasValue('entity_form')) { + $this->getEntityForm($this->menu)->submitForm($form, $form_state); + $this->menu->save(); + } + } /** @@ -150,4 +158,14 @@ public function setPlugin(PluginInspectionInterface $plugin) { $this->menu = $this->menuStorage->load($this->plugin->getDerivativeId()); } + /** + * Determines if the menu is currently overridden. + * + * @return bool + * TRUE if the menu is overrridden, otherwise false. + */ + public function isMenuOverridden() { + return \Drupal::config($this->menu->getEntityType()->getConfigPrefix() . '.' . $this->menu->id())->hasOverrides(); + } + } diff --git a/core/modules/settings_tray/tests/modules/settings_tray_override_test/settings_tray_override_test.info.yml b/core/modules/settings_tray/tests/modules/settings_tray_override_test/settings_tray_override_test.info.yml new file mode 100644 index 0000000000..89f9732feb --- /dev/null +++ b/core/modules/settings_tray/tests/modules/settings_tray_override_test/settings_tray_override_test.info.yml @@ -0,0 +1,7 @@ +name: 'Configuration override test for Settings Tray' +type: module +package: Testing +version: VERSION +core: 8.x +dependencies: + - settings_tray diff --git a/core/modules/settings_tray/tests/modules/settings_tray_override_test/settings_tray_override_test.services.yml b/core/modules/settings_tray/tests/modules/settings_tray_override_test/settings_tray_override_test.services.yml new file mode 100644 index 0000000000..b23035bde2 --- /dev/null +++ b/core/modules/settings_tray/tests/modules/settings_tray_override_test/settings_tray_override_test.services.yml @@ -0,0 +1,5 @@ +services: + settings_tray_override_test.overrider: + class: Drupal\settings_tray_override_test\ConfigOverrider + tags: + - { name: config.factory.override} diff --git a/core/modules/settings_tray/tests/modules/settings_tray_override_test/src/ConfigOverrider.php b/core/modules/settings_tray/tests/modules/settings_tray_override_test/src/ConfigOverrider.php new file mode 100644 index 0000000000..0dcd9e608c --- /dev/null +++ b/core/modules/settings_tray/tests/modules/settings_tray_override_test/src/ConfigOverrider.php @@ -0,0 +1,58 @@ + ['settings' => ['label' => 'Now this will be the label.']]]; + } + if (in_array('system.site', $names)) { + if (\Drupal::state()->get('settings_tray_override_test.site_name')) { + $overrides = $overrides + ['system.site' => ['name' => 'Llama Fan Club']]; + } + } + if (in_array('system.menu.main', $names)) { + if (\Drupal::state()->get('settings_tray_override_test.menu')) { + $overrides = $overrides + ['system.menu.main' => ['label' => 'Labely label']]; + } + } + return $overrides; + } + + /** + * {@inheritdoc} + */ + public function getCacheSuffix() { + return 'ConfigOverrider'; + } + + /** + * {@inheritdoc} + */ + public function createConfigObject($name, $collection = StorageInterface::DEFAULT_COLLECTION) { + return NULL; + } + + /** + * {@inheritdoc} + */ + public function getCacheableMetadata($name) { + return new CacheableMetadata(); + } + +} diff --git a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php index fcfecde400..5a6adb93df 100644 --- a/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php +++ b/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php @@ -5,6 +5,7 @@ use Drupal\block\Entity\Block; use Drupal\block_content\Entity\BlockContent; use Drupal\block_content\Entity\BlockContentType; +use Drupal\menu_link_content\Entity\MenuLinkContent; use Drupal\settings_tray_test\Plugin\Block\SettingsTrayFormAnnotationIsClassBlock; use Drupal\settings_tray_test\Plugin\Block\SettingsTrayFormAnnotationNoneBlock; use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait; @@ -43,6 +44,9 @@ class SettingsTrayBlockFormTest extends OffCanvasTestBase { // cause test failures. 'settings_tray_test_css', 'settings_tray_test', + 'settings_tray_override_test', + 'menu_ui', + 'menu_link_content', ]; /** @@ -75,7 +79,7 @@ public function testBlocks($theme, $block_plugin, $new_page_text, $element_selec $page = $this->getSession()->getPage(); $this->enableTheme($theme); $block = $this->placeBlock($block_plugin); - $block_selector = str_replace('_', '-', $this->getBlockSelector($block)); + $block_selector = $this->getBlockSelector($block); $block_id = $block->id(); $this->drupalGet('user'); @@ -267,8 +271,10 @@ protected function assertOffCanvasBlockFormIsValid() { * @param string $contextual_link_container * The element that contains the contextual links. If none provide the * $block_selector will be used. + * @param bool $has_confirm_form + * Determines if the block form should be confirmed. */ - protected function openBlockForm($block_selector, $contextual_link_container = '') { + protected function openBlockForm($block_selector, $contextual_link_container = '', $has_confirm_form = TRUE) { if (!$contextual_link_container) { $contextual_link_container = $block_selector; } @@ -283,7 +289,9 @@ protected function openBlockForm($block_selector, $contextual_link_container = ' $this->assertSession()->assertWaitOnAjaxRequest(); $this->click($block_selector); $this->waitForOffCanvasToOpen(); - $this->assertOffCanvasBlockFormIsValid(); + if ($has_confirm_form) { + $this->assertOffCanvasBlockFormIsValid(); + } } /** @@ -321,7 +329,7 @@ public function testQuickEditLinks() { $this->enableTheme($theme); $block = $this->placeBlock($block_plugin); - $block_selector = str_replace('_', '-', $this->getBlockSelector($block)); + $block_selector = $this->getBlockSelector($block); // Load the same page twice. foreach ([1, 2] as $page_load_times) { $this->drupalGet('node/' . $node->id()); @@ -531,7 +539,7 @@ public function testCustomBlockLinks() { * The CSS selector. */ public function getBlockSelector(Block $block) { - return '#block-' . $block->id(); + return '#block-' . str_replace('_', '-', $block->id()); } /** @@ -577,4 +585,95 @@ protected function getTestThemes() { }); } + /** + * Tests that blocks with configuration overrides are disabled. + */ + public function testOverriddenConfigRemoved() { + $web_assert = $this->assertSession(); + $page = $this->getSession()->getPage(); + $overridden_block = $this->placeBlock('system_powered_by_block', [ + 'id' => 'overridden_block', + 'label_display' => 1, + 'label' => 'This will be overridden.', + ]); + $this->drupalGet('user'); + $this->assertOverriddenBlockDisabled($overridden_block, 'Now this will be the label.'); + + // Test a non-overridden block does show the form in the off-canvas dialog. + $block = $this->placeBlock('system_powered_by_block', [ + 'label_display' => 1, + 'label' => 'Labely label', + ]); + $this->drupalGet('user'); + $block_selector = $this->getBlockSelector($block); + // Confirm the block is marked as Settings Tray editable. + $this->assertEquals('editable', $page->find('css', $block_selector)->getAttribute('data-drupal-settingstray')); + // Confirm the label is not overridden. + $web_assert->elementContains('css', $block_selector, 'Labely label'); + $this->enableEditMode(); + $this->openBlockForm($this->getBlockSelector($block)); + + // Confirm the branding block does include 'site_information' section when + // the site name is not overridden. + $branding_block = $this->placeBlock('system_branding_block'); + $this->drupalGet('user'); + $this->openBlockForm($this->getBlockSelector($branding_block)); + $web_assert->fieldExists('settings[site_information][site_name]'); + // Confirm the branding block does not include 'site_information' section + // when the site name is overridden. + $this->container->get('state')->set('settings_tray_override_test.site_name', TRUE); + $this->drupalGet('user'); + $this->openBlockForm($this->getBlockSelector($branding_block)); + $web_assert->fieldNotExists('settings[site_information][site_name]'); + + // Add a link or the menu will not render. + $menu_link_content = MenuLinkContent::create([ + 'title' => 'This is on the menu', + 'menu_name' => 'main', + 'link' => ['uri' => 'route:'], + ]); + $menu_link_content->save(); + // Confirm the menu block does include menu section when the menu is not + // overridden. + $block = $this->placeBlock('system_menu_block:main'); + $menu_block = $this->placeBlock('system_menu_block:main'); + $this->drupalGet('user'); + $this->openBlockForm($this->getBlockSelector($menu_block)); + $web_assert->elementExists('css', '#menu-overview'); + + // Confirm the menu block does not include menu section when the menu is + // overridden. + $this->container->get('state')->set('settings_tray_override_test.menu', TRUE); + $this->drupalGet('user'); + $this->openBlockForm($this->getBlockSelector($menu_block)); + $web_assert->elementNotExists('css', '#menu-overview'); + } + + /** + * Asserts that an overridden block has Settings Tray disabled. + * + * @param \Drupal\block\Entity\Block $overridden_block + * The overridden block. + * @param string $override_text + * The override text that should appear in the block. + */ + protected function assertOverriddenBlockDisabled(Block $overridden_block, $override_text) { + $web_assert = $this->assertSession(); + $page = $this->getSession()->getPage(); + $block_selector = $this->getBlockSelector($overridden_block); + $block_id = $overridden_block->id(); + // Confirm the block does not have a quick edit link. + $contextual_links = $page->findAll('css', "$block_selector .contextual-links li a"); + $this->assertNotEmpty($contextual_links); + foreach ($contextual_links as $link) { + $this->assertNotContains("/admin/structure/block/manage/$block_id/off-canvas", $link->getAttribute('href')); + } + // Confirm the block is not marked as Settings Tray editable. + $this->assertFalse($page->find('css', $block_selector) + ->hasAttribute('data-drupal-settingstray')); + + // Confirm the text is actually overridden. + $web_assert->elementContains('css', $this->getBlockSelector($overridden_block), $override_text); + } + }