πŸ‡ΊπŸ‡¦Ukraine @strayder

Account created on 18 March 2021, almost 4 years ago
#

Recent comments

πŸ‡ΊπŸ‡¦Ukraine strayder

Sorry for the confusion caused by the previous comments; they are outdated and no longer relevant. Here is the updated patch that you can use.

πŸ‡ΊπŸ‡¦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