layout_builder_ipe-1.0.x-dev/src/LayoutBuilder/LayoutBuilderUi.php
src/LayoutBuilder/LayoutBuilderUi.php
<?php
namespace Drupal\layout_builder_ipe\LayoutBuilder;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
use Drupal\layout_builder\Controller\LayoutRebuildTrait;
use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
use Drupal\layout_builder\SectionComponent;
use Drupal\layout_builder\SectionStorageInterface;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Service class for helping with altering the behavior of the LB UI.
*/
class LayoutBuilderUi {
use StringTranslationTrait;
use LayoutBuilderContextTrait;
use LayoutRebuildTrait;
const BEFORE = 'before';
const AFTER = 'after';
/**
* The current request.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* The layout tempstore repository.
*
* @var \Drupal\layout_builder\LayoutTempstoreRepositoryInterface
*/
protected $layoutTempstoreRepository;
/**
* Public constructor.
*
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
* The layout tempstore repository.
*/
public function __construct(RequestStack $request_stack, LayoutTempstoreRepositoryInterface $layout_tempstore_repository) {
$this->request = $request_stack->getCurrentRequest();
$this->layoutTempstoreRepository = $layout_tempstore_repository;
}
/**
* Create an additional "Add block" button.
*
* @param \Drupal\layout_builder\SectionComponent $component
* The section component holding a block.
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage.
* @param int $delta
* The delta of the section.
* @param string $placement
* One of self::BEFORE or self::AFTER to control where the link should be
* added respective to the given component.
*
* @return array
* A render array describing the button.
*/
public function createAddButton(SectionComponent $component, SectionStorageInterface $section_storage, $delta, $placement) {
$storage_type = $section_storage->getStorageType();
$storage_id = $section_storage->getStorageId();
$section = $section_storage->getSection($delta);
$layout = $section->getLayout($this->getPopulatedContexts($section_storage));
$layout_settings = $section->getLayoutSettings();
$section_label = !empty($layout_settings['label']) ? $layout_settings['label'] : $this->t('Section @section', ['@section' => $delta + 1]);
$layout_definition = $layout->getPluginDefinition();
$region_labels = $layout_definition->getRegionLabels();
$region = $component->getRegion();
$classes = [
'use-ajax',
'layout-builder__link',
'layout-builder__link--add',
];
$position = NULL;
if ($placement == self::BEFORE) {
$classes[] = 'link-before';
$position = $component->getWeight();
}
if ($placement == self::AFTER) {
$classes[] = 'link-after';
$position = $component->getWeight() + 1;
}
$icon = Markup::create(file_get_contents('core/misc/icons/bebebe/plus.svg'));
$add_link = [
'#type' => 'link',
'#title' => $this->t('@icon<span class="visually-hidden">in @section, @region region</span>', [
'@icon' => $icon,
'@section' => $section_label,
'@region' => $region_labels[$region],
]),
'#url' => Url::fromRoute('layout_builder.choose_block',
[
'section_storage_type' => $storage_type,
'section_storage' => $storage_id,
'delta' => $delta,
'region' => $region,
],
[
'query' => [
'position' => $position,
],
'attributes' => [
'class' => $classes,
'data-dialog-type' => 'dialog',
'data-dialog-renderer' => 'off_canvas',
],
],
),
];
return $add_link;
}
/**
* Handle a form submit of block forms.
*
* This method takes care to only do something, if the form submission is the
* result of a form triggered by a button click on buttons created via
* self::createAddButton().
* The logic for positioning the element comes from
* \Drupal\layout_builder\Controller\MoveBlockController::build().
*
* @param array $form
* The form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state interface.
*/
public function blockFormSubmit(array &$form, FormStateInterface $form_state) {
$position = $this->request->query->get('position');
if ($position === NULL || $position === '') {
return;
}
/** @var \Drupal\layout_builder\Form\AddBlockForm $form_object */
$form_object = $form_state->getFormObject();
$current_section = $form_object->getCurrentSection();
// Get the new component and remove it from the current section, so that it
// can be re-added at the specified position.
$new_component = $form_object->getCurrentComponent();
$current_section->removeComponent($new_component->getUuid());
// Find the preceding block, based on the specified position, so that we
// know after which element the component must be added.
$preceding_block_uuid = NULL;
foreach ($current_section->getComponents() as $component) {
if ($component->getWeight() == $position - 1) {
$preceding_block_uuid = $component->getUuid();
break;
}
}
// Now either insert the component after the preceding block, or put it
// first if there is no preceding block. This will internally also adjust
// the weight of all other components, so that the result is stable.
if (isset($preceding_block_uuid)) {
$current_section->insertAfterComponent($preceding_block_uuid, $new_component);
}
else {
$current_section->insertComponent(0, $new_component);
}
// Now update the section storage in the tempstore.
$section_storage = $form_object->getSectionStorage();
$this->layoutTempstoreRepository->set($section_storage);
}
}
