Support for Layout Builder iFrame Modal

Created on 20 September 2021, about 3 years ago
Updated 29 August 2024, 4 months ago

Problem/Motivation

Currently we are using https://www.drupal.org/project/layout_builder_iframe_modal β†’ for popping out complex block forms for the users. We went with the iframe module over https://www.drupal.org/project/layout_builder_modal β†’ because the modal module uses the front end theme which isn't super with backend ui elements. The iframe uses the backend theme making it easier for the user.

We want to implement this module but currently it's broken in the iframe and not sure how much trouble it would be to get working. We are using the Drupal's Claro theme.

✨ Feature request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States smustgrave

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡³πŸ‡¬Nigeria chike Nigeria

    Using Drupal 10.0.3, 'layout_builder_iframe_modal' 1.3.0 and Boostrap Barrio theme, I am having this issue as this module is broken in the iframe.

    I attached screenshots of how it looks.

  • πŸ‡―πŸ‡΄Jordan Rajab Natshah Jordan

    ✨ Limit Layout Builder Blocks not to work in the dashboards route Needs work
    Switching the theme for front-end them is hard.
    Layout Builder iFrame Modal is not practical to use with Layout Builder Blocks.
    the system and them for Layout Styles should attached and changed to work with the back-end them.

    To me it's not doable. Hard to manage.

  • πŸ‡―πŸ‡΄Jordan Rajab Natshah Jordan

    Switching back to Layout Builder Modal with supports for Claro and Gin

  • πŸ‡ΊπŸ‡ΈUnited States dalemoore

    I wonder if it would be possible to take a page from Layout Builder Component Attributes β†’ and have a different setting in the contextual menu just for the block style settings? If you have that module enabled, for a block you get four options:

    • Configure
    • Manage attributes (this is the menu item the module adds)
    • Move
    • Remove block

    Then you could continue to edit the block content through "Configure", which will open in a modal window, but control the Bootstrap Styles under a separate link within the contextual menu so that they're in the right-hand tray not the popup.

  • πŸ‡ΊπŸ‡¦Ukraine strayder

    The code below implements this. https://www.drupal.org/project/layout_builder_blocks/issues/3238141#comm... ✨ Support for Layout Builder iFrame Modal Active

    web/modules/custom/YOUR MODULE/src/Form/ManageComponentStylesForm.php

    <?php
    
    namespace Drupal\YOUR MODULE\Form;
    
    use Drupal\bootstrap_styles\StylesGroup\StylesGroupManager;
    use Drupal\Component\Utility\Html;
    use Drupal\Core\Ajax\AjaxFormHelperTrait;
    use Drupal\Core\Ajax\AjaxResponse;
    use Drupal\Core\Config\ConfigFactoryInterface;
    use Drupal\Core\Entity\EntityRepositoryInterface;
    use Drupal\Core\Form\FormBase;
    use Drupal\Core\Form\FormStateInterface;
    use Drupal\layout_builder\Controller\LayoutRebuildTrait;
    use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
    use Drupal\layout_builder\SectionStorageInterface;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    
    /**
     * Provides a form for managing block attributes without using tabs.
     */
    class ManageComponentStylesForm extends FormBase {
    
      use AjaxFormHelperTrait;
      use LayoutRebuildTrait;
    
      /**
       * The section storage.
       *
       * @var \Drupal\layout_builder\SectionStorageInterface
       */
      protected SectionStorageInterface $sectionStorage;
    
      /**
       * The section delta.
       *
       * @var int
       */
      protected int $delta;
    
      /**
       * The component uuid.
       *
       * @var string
       */
      protected string $uuid;
    
      /**
       * The Layout Tempstore.
       *
       * @var \Drupal\layout_builder\LayoutTempstoreRepositoryInterface
       */
      protected LayoutTempstoreRepositoryInterface $layoutTempstore;
    
      /**
       * The configuration factory.
       *
       * @var \Drupal\Core\Config\ConfigFactoryInterface
       */
      protected $configFactory;
    
      /**
       * The entity repository.
       *
       * @var \Drupal\Core\Entity\EntityRepositoryInterface
       */
      protected EntityRepositoryInterface $entityRepository;
    
      /**
       * The styles group manager.
       *
       * @var \Drupal\bootstrap_styles\StylesGroup\StylesGroupManager
       */
      protected StylesGroupManager $stylesGroupManager;
    
      /**
       * Constructs a new ManageComponentAttributesForm.
       *
       * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
       *   The layout tempstore.
       * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
       *   The configuration factory.
       * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
       *   The entity repository.
       * @param \Drupal\bootstrap_styles\StylesGroup\StylesGroupManager $styles_group_manager
       *   The styles group manager.
       */
      public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, StylesGroupManager $styles_group_manager) {
        $this->layoutTempstore = $layout_tempstore_repository;
        $this->configFactory = $config_factory;
        $this->entityRepository = $entity_repository;
        $this->stylesGroupManager = $styles_group_manager;
      }
    
      /**
       * {@inheritdoc}
       */
      public static function create(ContainerInterface $container) {
        return new static(
          $container->get('layout_builder.tempstore_repository'),
          $container->get('config.factory'),
          $container->get('entity.repository'),
          $container->get('plugin.manager.bootstrap_styles_group')
        );
      }
    
      /**
       * {@inheritdoc}
       */
      public function getFormId(): string {
        return 'YOUR MODULE_manage_attributes_form';
      }
    
      /**
       * Builds the attributes form without tabs.
       *
       * @param array $form
       *   An associative array containing the structure of the form.
       * @param \Drupal\Core\Form\FormStateInterface $form_state
       *   The current state of the form.
       * @param \Drupal\layout_builder\SectionStorageInterface|null $section_storage
       *   The section storage being configured.
       * @param int|null $delta
       *   The original delta of the section.
       * @param string|null $uuid
       *   The UUID of the block being updated.
       *
       * @return array
       *   The form array.
       *
       * @throws \Drupal\Component\Plugin\Exception\PluginException
       * @throws \Drupal\Core\Entity\EntityStorageException
       */
      public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, int $delta = NULL, string $uuid = NULL): array {
        $this->sectionStorage = $section_storage;
        $this->delta = $delta;
        $this->uuid = $uuid;
    
        $section = $section_storage->getSection($delta);
        $component = $section->getComponent($uuid);
        $block_plugin_id = $component->getPluginId();
    
        // Check access to functionality.
        $allowed = $this->checkBlockRestrictions($block_plugin_id);
    
        if ($allowed) {
          $configuration = [
            'bootstrap_styles' => [
              'block_style' => [],
            ],
          ];
    
          if ($component->get('bootstrap_styles')) {
            $bootstrap_styles = $component->get('bootstrap_styles');
            if (isset($bootstrap_styles['block_style'])) {
              $configuration['bootstrap_styles'] = $bootstrap_styles;
            }
          }
    
          // Add fields to manage attributes.
          $form['appearance'] = [
            '#type' => 'details',
            '#title' => $this->t('Styles'),
            '#open' => TRUE,
          ];
    
          $form['appearance'] += $this->stylesGroupManager->buildStylesFormElements(
            $form['appearance'],
            $form_state,
            $configuration['bootstrap_styles']['block_style'],
            'layout_builder_blocks.styles'
          );
    
          // Attach required libraries.
          $form['#attached']['library'][] = 'bootstrap_styles/layout_builder_form_style';
        }
    
        $form['#tree'] = TRUE;
        $form['#id'] = Html::cleanCssIdentifier($this->getFormId());
    
        $form['actions']['submit'] = [
          '#type' => 'submit',
          '#value' => $this->t('Update'),
          '#button_type' => 'primary',
        ];
    
        if ($this->isAjax()) {
          $form['actions']['submit']['#ajax']['callback'] = '::ajaxSubmit';
        }
    
        return $form;
      }
    
      /**
       * Checks block restrictions.
       *
       * @param string $block_plugin_id
       *   ID of the block plugin.
       *
       * @return bool
       *   TRUE if the block is allowed.
       *
       * @throws \Drupal\Core\Entity\EntityStorageException
       */
      protected function checkBlockRestrictions(string $block_plugin_id): bool {
        $config = $this->configFactory->get('YOUR MODULE.settings');
        $bundle = FALSE;
    
        if (str_starts_with($block_plugin_id, "block_content:")) {
          $uuid = str_replace('block_content:', '', $block_plugin_id);
          $bundle = $this->entityRepository->loadEntityByUuid('block_content', $uuid)->bundle();
        }
    
        return empty($config->get('block_restrictions'))
          || in_array($block_plugin_id, $config->get('block_restrictions'), TRUE)
          || ($bundle && in_array('inline_block:' . $bundle, $config->get('block_restrictions'), TRUE));
      }
    
      /**
       * {@inheritdoc}
       */
      public function submitForm(array &$form, FormStateInterface $form_state): void {
        $delta = $this->getSelectedDelta($form_state);
        $section = $this->sectionStorage->getSection($delta);
        $component = $section->getComponent($this->uuid);
    
        $bootstrap_styles = [
          'block_style' => $this->stylesGroupManager->submitStylesFormElements($form['appearance'], $form_state, ['appearance'], [], 'layout_builder_blocks.styles'),
        ];
    
        $component->set('bootstrap_styles', $bootstrap_styles);
        $this->layoutTempstore->set($this->sectionStorage);
        $form_state->setRedirectUrl($this->sectionStorage->getLayoutBuilderUrl());
      }
    
      /**
       * AJAX submit callback.
       */
      public function ajaxSubmit(array &$form, FormStateInterface $form_state): AjaxResponse {
        return $this->rebuildAndClose($this->sectionStorage);
      }
    
      /**
       * {@inheritdoc}
       */
      protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state): AjaxResponse {
        return $this->rebuildAndClose($this->sectionStorage);
      }
    
      /**
       * Gets the selected delta.
       *
       * @param \Drupal\Core\Form\FormStateInterface $form_state
       *   The form state.
       *
       * @return int
       *   The section delta.
       */
      protected function getSelectedDelta(FormStateInterface $form_state): int {
        if ($form_state->hasValue('region')) {
          return (int) explode(':', $form_state->getValue('region'))[0];
        }
        return (int) $this->delta;
      }
    
    }
    

    YOUR MODULE.module

    /**
     * Implements hook_module_implements_alter().
     */
    function YOUR MODULE_module_implements_alter(&$implementations, $hook): void {
      if ($hook === 'form_alter' && isset($implementations['layout_builder_blocks'])) {
        unset($implementations['layout_builder_blocks']);
      }
    }
    

    YOUR MODULE.routing.yml

    YOUR MODULE.manage_attributes:
      path: '/YOUR MODULE/update/block-styles/{section_storage_type}/{section_storage}/{delta}/{uuid}'
      defaults:
        _form: '\Drupal\YOUR MODULE\Form\ManageComponentStylesForm'
        _title: 'Manage styles'
      requirements:
        _permission: 'manage layout builder component attributes'
        _layout_builder_access: 'view'
      options:
        _admin_route: TRUE
        parameters:
          section_storage:
            layout_builder_tempstore: TRUE
    
    

    YOUR MODULE.links.contextual.yml

    layout_builder_block_styles:
      title: 'Manage styles'
      route_name: 'YOUR MODULE.manage_attributes'
      group: 'layout_builder_block'
      options:
        attributes:
          class: ['use-ajax']
          data-dialog-type: dialog
          data-dialog-renderer: off_canvas
    
Production build 0.71.5 2024