diff --git a/core/core.services.yml b/core/core.services.yml index 2f7da56..d2aa505 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -569,6 +569,9 @@ services: entity.autocomplete_matcher: class: Drupal\Core\Entity\EntityAutocompleteMatcher arguments: ['@plugin.manager.entity_reference_selection'] + block_form.manager: + class: Drupal\Core\Block\BlockFormManager + arguments: ['@class_resolver'] plugin.manager.entity_reference_selection: class: Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager parent: default_plugin_manager diff --git a/core/modules/outside_in/src/Block/OutsideInBlockManager.php b/core/lib/Drupal/Core/Block/BlockFormManager.php similarity index 91% rename from core/modules/outside_in/src/Block/OutsideInBlockManager.php rename to core/lib/Drupal/Core/Block/BlockFormManager.php index 474f8a0..f866706 100644 --- a/core/modules/outside_in/src/Block/OutsideInBlockManager.php +++ b/core/lib/Drupal/Core/Block/BlockFormManager.php @@ -1,17 +1,17 @@ processDefinitionCategory($definition); + + // If no default form is defined and this plugin implements + // \Drupal\Core\Plugin\PluginFormInterface, use that for the default form. + if (!isset($definition['form']['default']) && is_subclass_of($definition['class'], PluginFormInterface::class)) { + $definition['form']['default'] = $definition['class']; + } } /** diff --git a/core/modules/outside_in/src/OperationAwareFormInterface.php b/core/lib/Drupal/Core/Form/OperationAwareFormInterface.php similarity index 91% rename from core/modules/outside_in/src/OperationAwareFormInterface.php rename to core/lib/Drupal/Core/Form/OperationAwareFormInterface.php index cf31c58..8172bd7 100644 --- a/core/modules/outside_in/src/OperationAwareFormInterface.php +++ b/core/lib/Drupal/Core/Form/OperationAwareFormInterface.php @@ -1,6 +1,6 @@ storage = $entity_manager->getStorage('block'); $this->manager = $manager; $this->contextRepository = $context_repository; $this->language = $language; $this->themeHandler = $theme_handler; + $this->blockFormManager = $block_form_manager; } /** @@ -99,7 +111,8 @@ public static function create(ContainerInterface $container) { $container->get('plugin.manager.condition'), $container->get('context.repository'), $container->get('language_manager'), - $container->get('theme_handler') + $container->get('theme_handler'), + $container->get('block_form.manager') ); } @@ -120,7 +133,7 @@ public function form(array $form, FormStateInterface $form_state) { $form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts()); $form['#tree'] = TRUE; - $form['settings'] = $entity->getPlugin()->buildConfigurationForm(array(), $form_state); + $form['settings'] = $this->getPluginForm($this->entity->getPlugin())->buildConfigurationForm(array(), $form_state); $form['visibility'] = $this->buildVisibilityInterface([], $form_state); // If creating a new block, calculate a safe default machine name. @@ -282,7 +295,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) { // settings form element, so just pass that to the block for validation. $settings = (new FormState())->setValues($form_state->getValue('settings')); // Call the plugin validate handler. - $this->entity->getPlugin()->validateConfigurationForm($form, $settings); + $this->getPluginForm($this->entity->getPlugin())->validateConfigurationForm($form, $settings); // Update the original form values. $form_state->setValue('settings', $settings->getValues()); $this->validateVisibility($form, $form_state); @@ -322,15 +335,14 @@ protected function validateVisibility(array $form, FormStateInterface $form_stat public function submitForm(array &$form, FormStateInterface $form_state) { parent::submitForm($form, $form_state); - $entity = $this->entity; // The Block Entity form puts all block plugin form elements in the // settings form element, so just pass that to the block for submission. // @todo Find a way to avoid this manipulation. $settings = (new FormState())->setValues($form_state->getValue('settings')); // Call the plugin submit handler. - $entity->getPlugin()->submitConfigurationForm($form, $settings); - $block = $entity->getPlugin(); + $block = $this->entity->getPlugin(); + $this->getPluginForm($block)->submitConfigurationForm($form, $settings); // If this block is context-aware, set the context mapping. if ($block instanceof ContextAwarePluginInterface && $block->getContextDefinitions()) { $context_mapping = $settings->getValue('context_mapping', []); @@ -339,7 +351,30 @@ public function submitForm(array &$form, FormStateInterface $form_state) { // Update the original form values. $form_state->setValue('settings', $settings->getValues()); - // Submit visibility condition settings. + $this->submitVisibility($form, $form_state); + + // Save the settings of the plugin. + $this->entity->save(); + + drupal_set_message($this->t('The block configuration has been saved.')); + $form_state->setRedirect( + 'block.admin_display_theme', + array( + 'theme' => $form_state->getValue('theme'), + ), + array('query' => array('block-placement' => Html::getClass($this->entity->id()))) + ); + } + + /** + * Helper function to independently submit the visibility UI. + * + * @param array $form + * A nested array form elements comprising the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + */ + protected function submitVisibility(array $form, FormStateInterface $form_state) { foreach ($form_state->getValue('visibility') as $condition_id => $values) { // Allow the condition to submit the form. $condition = $form_state->get(['conditions', $condition_id]); @@ -354,20 +389,8 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $condition_configuration = $condition->getConfiguration(); $form_state->setValue(['visibility', $condition_id], $condition_configuration); // Update the visibility conditions on the block. - $entity->getVisibilityConditions()->addInstanceId($condition_id, $condition_configuration); + $this->entity->getVisibilityConditions()->addInstanceId($condition_id, $condition_configuration); } - - // Save the settings of the plugin. - $entity->save(); - - drupal_set_message($this->t('The block configuration has been saved.')); - $form_state->setRedirect( - 'block.admin_display_theme', - array( - 'theme' => $form_state->getValue('theme'), - ), - array('query' => array('block-placement' => Html::getClass($this->entity->id()))) - ); } /** @@ -402,4 +425,17 @@ public function getUniqueMachineName(BlockInterface $block) { return $machine_default; } + /** + * Retrieves the plugin form for a given block and operation. + * + * @param \Drupal\Core\Block\BlockPluginInterface $block + * The block plugin. + * + * @return \Drupal\Core\Plugin\PluginFormInterface + * The plugin form for the block. + */ + protected function getPluginForm(BlockPluginInterface $block) { + return $this->blockFormManager->getFormObject($block, $this->operation); + } + } diff --git a/core/modules/outside_in/tests/modules/offcanvas_test/src/Form/OffCanvasForm.php b/core/modules/block/tests/modules/block_test/src/Form/SecondaryBlockForm.php similarity index 81% rename from core/modules/outside_in/tests/modules/offcanvas_test/src/Form/OffCanvasForm.php rename to core/modules/block/tests/modules/block_test/src/Form/SecondaryBlockForm.php index ecca616..3095963 100644 --- a/core/modules/outside_in/tests/modules/offcanvas_test/src/Form/OffCanvasForm.php +++ b/core/modules/block/tests/modules/block_test/src/Form/SecondaryBlockForm.php @@ -1,15 +1,15 @@ method('getStorage') ->will($this->returnValue($this->storage)); + $this->blockFormManager = $this->prophesize(BlockFormManagerInterface::class); } /** @@ -99,7 +108,7 @@ public function testGetUniqueMachineName() { ->method('getQuery') ->will($this->returnValue($query)); - $block_form_controller = new BlockForm($this->entityManager, $this->conditionManager, $this->contextRepository, $this->language, $this->themeHandler); + $block_form_controller = new BlockForm($this->entityManager, $this->conditionManager, $this->contextRepository, $this->language, $this->themeHandler, $this->blockFormManager->reveal()); // Ensure that the block with just one other instance gets the next available // name suggestion. diff --git a/core/modules/outside_in/css/outside_in.module.css b/core/modules/outside_in/css/outside_in.module.css index a199174..2578325 100644 --- a/core/modules/outside_in/css/outside_in.module.css +++ b/core/modules/outside_in/css/outside_in.module.css @@ -3,7 +3,7 @@ * Styling for Outside-In module. */ -/* style the offcanvas container */ +/* Style the offcanvas container */ #offcanvas { box-sizing: border-box; position: fixed; @@ -12,51 +12,51 @@ display: inline-block; width: 25%; -webkit-transform: translateX(100%); - -moz-transform: translateX(100%); - -o-transform: translateX(100%); - -ms-transform: translateX(100%); - transform: translateX(100%); + -moz-transform: translateX(100%); + -o-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); /* 2s delay matches transition speed to transform speed */ -webkit-transition: all 1s ease-in-out 2s; - -moz-transition: all 1s ease-in-out 2s; - transition: all 1s ease-in-out 2s; + -moz-transition: all 1s ease-in-out 2s; + transition: all 1s ease-in-out 2s; z-index: 1000; } [dir="rtl"] #offcanvas { text-align: right; -webkit-transform: translateX(-100%); - -moz-transform: translateX(-100%); - -o-transform: translateX(-100%); - -ms-transform: translateX(-100%); - transform: translateX(-100%); + -moz-transform: translateX(-100%); + -o-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); } #main-canvas-wrapper.js-tray-open #offcanvas { -webkit-transform: translateX(0); - -moz-transform: translateX(0); - -o-transform: translateX(0); - -ms-transform: translateX(0); - transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); } #main-canvas-wrapper #main-canvas { display: inline-block; width: 100%; -webkit-transition: all 1s ease-in-out; - -moz-transition: all 1s ease-in-out; - transition: all 1s ease-in-out; + -moz-transition: all 1s ease-in-out; + transition: all 1s ease-in-out; } #main-canvas-wrapper.js-tray-open #main-canvas { left: 0; /* LTR */ width: 75%; -webkit-transition: all 1s ease-in-out; - -moz-transition: all 1s ease-in-out; - transition: all 1s ease-in-out; + -moz-transition: all 1s ease-in-out; + transition: all 1s ease-in-out; } [dir="rtl"] #main-canvas-wrapper.js-tray-open #main-canvas { right: 0; } -/* button that closes the offcanvas tray */ +/* Button that closes the offcanvas tray */ #offcanvas > button.offcanvasClose, -#offcanvas > button.offcanvasClose:hover { /* todo: add hover state */ +#offcanvas > button.offcanvasClose:hover { /* @todo add hover state */ position: absolute; right: 15px; /* LTR */ top: 15px; @@ -95,9 +95,8 @@ background-color: rgba(0,0,0,0.1); } -/* Highlight editable regions in edit mode -@tod Clean up this css. -*/ +/* Highlight editable regions in edit mode. */ +/* @todo Clean up this css. */ #main-canvas.js-outside-in-edit-mode .outside-in-editable { outline: -webkit-focus-ring-color auto 2px; outline-color: -webkit-focus-ring-color; diff --git a/core/modules/outside_in/css/outside_in.theme.css b/core/modules/outside_in/css/outside_in.theme.css index b67f380..1887e35 100644 --- a/core/modules/outside_in/css/outside_in.theme.css +++ b/core/modules/outside_in/css/outside_in.theme.css @@ -3,7 +3,7 @@ * Visual styling for Outside-In module. */ -/* style the offcanvas container */ +/* Style the offcanvas container */ div#offcanvas { background: #fff; border-left: 1px solid #ddd; /* LTR */ @@ -13,4 +13,3 @@ div#offcanvas { border-right: 1px solid #ddd; box-shadow: 2px 3px 1px 1px rgba(0, 0, 0, 0.3333); } - diff --git a/core/modules/outside_in/js/outside_in.js b/core/modules/outside_in/js/outside_in.js index 70684df..8fd0f42 100644 --- a/core/modules/outside_in/js/outside_in.js +++ b/core/modules/outside_in/js/outside_in.js @@ -75,7 +75,7 @@ Drupal.ajax(element_settings); }); - // Bind a listener to all 'Quick Edit' links for blocks + // Bind a listener to all 'Quick Edit' links for blocks // Click "Edit" button in toolbar to force Contextual Edit which starts // Outside In edit mode also. data.$el.find('.outside-inblock-configure a').click(function (e) { diff --git a/core/modules/outside_in/outside_in.module b/core/modules/outside_in/outside_in.module index bfff508..db122c5 100644 --- a/core/modules/outside_in/outside_in.module +++ b/core/modules/outside_in/outside_in.module @@ -71,19 +71,6 @@ function outside_in_page_bottom(array &$page_bottom) { } /** - * Implements hook_block_alter(). - */ -function outside_in_block_alter(&$definitions) { - foreach ($definitions as &$definition) { - // If no default form is defined and this plugin implements - // \Drupal\Core\Plugin\PluginFormInterface, use that for the default form. - if (!isset($definition['form']['default']) && is_subclass_of($definition['class'], PluginFormInterface::class)) { - $definition['form']['default'] = $definition['class']; - } - } -} - -/** * Implements hook_entity_type_build(). */ function outside_in_entity_type_build(array &$entity_types) { diff --git a/core/modules/outside_in/outside_in.services.yml b/core/modules/outside_in/outside_in.services.yml index a71843f..c240a18 100644 --- a/core/modules/outside_in/outside_in.services.yml +++ b/core/modules/outside_in/outside_in.services.yml @@ -4,9 +4,7 @@ services: arguments: ['@title_resolver', '@renderer'] tags: - { name: render.main_content_renderer, format: drupal_offcanvas } - outside_in.block.manager: - class: Drupal\outside_in\Block\OutsideInBlockManager - arguments: ['@class_resolver'] + outside_in.info: class: Drupal\outside_in\PageInfo arguments: ['@current_route_match', '@theme.negotiator.admin_theme'] diff --git a/core/modules/outside_in/src/Block/BlockEntityOffCanvasForm.php b/core/modules/outside_in/src/Block/BlockEntityOffCanvasForm.php index 2c5ad58..0445f0e 100644 --- a/core/modules/outside_in/src/Block/BlockEntityOffCanvasForm.php +++ b/core/modules/outside_in/src/Block/BlockEntityOffCanvasForm.php @@ -2,77 +2,34 @@ namespace Drupal\outside_in\Block; -use Drupal\Core\Entity\EntityForm; +use Drupal\block\BlockForm; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Plugin\Context\ContextRepositoryInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; /** * @todo. */ -class BlockEntityOffCanvasForm extends EntityForm { +class BlockEntityOffCanvasForm extends BlockForm { /** - * The block entity. - * - * @var \Drupal\block\BlockInterface - */ - protected $entity; - - /** - * The block manager. - * - * @var \Drupal\outside_in\Block\OutsideInBlockManagerInterface - */ - protected $blockManager; - - /** - * The context repository service. - * - * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface - */ - protected $contextRepository; - - /** - * BlockEntityOffCanvasForm constructor. - * - * @param \Drupal\outside_in\Block\OutsideInBlockManagerInterface $block_manager - * The block manager. - * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository - * The lazy context repository service. + * {@inheritdoc} */ - public function __construct(OutsideInBlockManagerInterface $block_manager, ContextRepositoryInterface $context_repository) { - $this->contextRepository = $context_repository; - $this->blockManager = $block_manager; + protected function buildVisibilityInterface(array $form, FormStateInterface $form_state) { + // Do not display the visibility. + return []; } /** * {@inheritdoc} */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('outside_in.block.manager'), - $container->get('context.repository') - ); + protected function validateVisibility(array $form, FormStateInterface $form_state) { + // Intentionally empty. } /** * {@inheritdoc} */ - public function form(array $form, FormStateInterface $form_state) { - // Store theme settings in $form_state for use below. - $form_state->set('block_theme', $this->entity->getTheme()); - - // Store the gathered contexts in the form state for other objects to use - // during form building. - $form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts()); - - $form['#tree'] = TRUE; - $form['#attached']['library'][] = 'block/drupal.block.admin'; - - $form['settings'] = $this->blockManager->getFormObject($this->entity->getPlugin(), 'offcavnas')->buildConfigurationForm([], $form_state); - - return $form; + protected function submitVisibility(array $form, FormStateInterface $form_state) { + // Intentionally empty. } } diff --git a/core/modules/outside_in/src/PageInfo.php b/core/modules/outside_in/src/PageInfo.php index 22472d8..649439a 100644 --- a/core/modules/outside_in/src/PageInfo.php +++ b/core/modules/outside_in/src/PageInfo.php @@ -10,7 +10,6 @@ */ class PageInfo { - /** * The admin theme negotiator. * diff --git a/core/modules/outside_in/tests/modules/offcanvas_test/src/Plugin/Block/TestBlock.php b/core/modules/outside_in/tests/modules/offcanvas_test/src/Plugin/Block/TestBlock.php index 2866311..da72f9b 100644 --- a/core/modules/outside_in/tests/modules/offcanvas_test/src/Plugin/Block/TestBlock.php +++ b/core/modules/outside_in/tests/modules/offcanvas_test/src/Plugin/Block/TestBlock.php @@ -10,9 +10,6 @@ * * @Block( * id = "offcanvas_links_block", - * form = { - * "offcanvas" = "\Drupal\offcanvas_test\Form\OffCanvasForm" - * }, * admin_label = @Translation("Off-canvas test block") * ) */ diff --git a/core/modules/outside_in/tests/src/Kernel/MultipleBlockFormTest.php b/core/modules/outside_in/tests/src/Kernel/MultipleBlockFormTest.php deleted file mode 100644 index 0899585..0000000 --- a/core/modules/outside_in/tests/src/Kernel/MultipleBlockFormTest.php +++ /dev/null @@ -1,37 +0,0 @@ -createInstance('offcanvas_links_block'); - - $form_object1 = \Drupal::service('outside_in.block.manager')->getFormObject($block, 'default'); - $form_object2 = \Drupal::service('outside_in.block.manager')->getFormObject($block, 'offcanvas'); - - // Assert that the block itself is used for the default form. - $this->assertSame($block, $form_object1); - - $expected_offcanvas = new OffCanvasForm(); - $expected_offcanvas->setOperation('offcanvas'); - $this->assertEquals($expected_offcanvas, $form_object2); - } - -} diff --git a/core/tests/Drupal/KernelTests/Core/Block/MultipleBlockFormTest.php b/core/tests/Drupal/KernelTests/Core/Block/MultipleBlockFormTest.php new file mode 100644 index 0000000..ad13628 --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Block/MultipleBlockFormTest.php @@ -0,0 +1,37 @@ +createInstance('test_multiple_forms_block'); + + $form_object1 = \Drupal::service('block_form.manager')->getFormObject($block, 'default'); + $form_object2 = \Drupal::service('block_form.manager')->getFormObject($block, 'secondary'); + + // Assert that the block itself is used for the default form. + $this->assertSame($block, $form_object1); + + $expected_secondary = new SecondaryBlockForm(); + $expected_secondary->setOperation('secondary'); + $this->assertEquals($expected_secondary, $form_object2); + } + +} diff --git a/core/modules/outside_in/tests/src/Unit/OutsideInBlockManagerTest.php b/core/tests/Drupal/Tests/Core/Block/BlockFormManagerTest.php similarity index 91% rename from core/modules/outside_in/tests/src/Unit/OutsideInBlockManagerTest.php rename to core/tests/Drupal/Tests/Core/Block/BlockFormManagerTest.php index 1158516..7ea0e06 100644 --- a/core/modules/outside_in/tests/src/Unit/OutsideInBlockManagerTest.php +++ b/core/tests/Drupal/Tests/Core/Block/BlockFormManagerTest.php @@ -1,21 +1,21 @@ classResolver = $this->prophesize(ClassResolverInterface::class); - $this->manager = new OutsideInBlockManager($this->classResolver->reveal()); + $this->manager = new BlockFormManager($this->classResolver->reveal()); } /**