diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml index 6e94ed74d2..6984c9b040 100644 --- a/core/modules/layout_builder/layout_builder.services.yml +++ b/core/modules/layout_builder/layout_builder.services.yml @@ -45,6 +45,11 @@ services: arguments: ['@current_user'] tags: - { name: event_subscriber } + layout_builder.block_component_preview_form_replace_subscriber: + class: Drupal\layout_builder\EventSubscriber\BlockComponentPreviewFormReplace + arguments: ['@renderer'] + tags: + - { name: event_subscriber } logger.channel.layout_builder: parent: logger.channel_base arguments: ['layout_builder'] diff --git a/core/modules/layout_builder/src/EventSubscriber/BlockComponentPreviewFormReplace.php b/core/modules/layout_builder/src/EventSubscriber/BlockComponentPreviewFormReplace.php new file mode 100644 index 0000000000..3f40d67dce --- /dev/null +++ b/core/modules/layout_builder/src/EventSubscriber/BlockComponentPreviewFormReplace.php @@ -0,0 +1,108 @@ +renderer = $renderer; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + // Very low priority - we want this to occur last since we perform early + // rendering of block components and want the most complete render array + // before doing that. + $events[LayoutBuilderEvents::SECTION_COMPONENT_BUILD_RENDER_ARRAY] = ['onBuildRender', -1000]; + return $events; + } + + /** + * Change forms to divs if in layout builder's preview mode. + * + * @param \Drupal\layout_builder\Event\SectionComponentBuildRenderArrayEvent $event + * The section component render event. + */ + public function onBuildRender(SectionComponentBuildRenderArrayEvent $event) { + $build = $event->getBuild(); + if ($event->inPreview() && isset($build['content']) && is_array($build['content'])) { + $build['content'] = $this->convertFormsToDiv($build['content']); + $event->setBuild($build); + } + } + + /** + * Convert form tags to div when displayed in the Layout Builder UI form. + * + * @param array $content + * The render array of the block. + */ + protected function convertFormsToDiv(array $content) { + // Render the block content early so we can parse the HTML. + // We keep an original copy around so we can return that if no forms are + // found. This allows us to only perform the early rendering when + // necessary. + $orginal_content = $content; + $markup = $this->renderer->render($content); + $html = Html::load((string) $markup); + + $forms = $html->getElementsByTagName('form'); + if ($forms->length) { + // Iteratve over each form and swap the form element with a div. + while ($form = $forms->item($forms->length - 1)) { + $form_children = []; + foreach ($form->childNodes as $form_child) { + $form_children[] = $form_child; + } + $replacement_div = $html->createElement('div'); + foreach ($form_children as $form_child) { + $replacement_div->appendChild($form_child); + } + foreach ($form->attributes as $form_attr_name => $form_attr) { + $replacement_div->setAttribute($form_attr_name, $form_attr->nodeValue); + } + $form->parentNode->replaceChild($replacement_div, $form); + } + $content['#markup'] = $html->saveHTML($html->getElementsByTagName('body')->item(0)); + return $content; + } + else { + return $orginal_content; + } + } + +}