diff --git a/layout_paragraphs.module b/layout_paragraphs.module index 8354b5278df2c8e502c56d08c32e0cc340514dda..ebdf26d81f3fa4dbf037b2806bb10eb0e36e8e53 100644 --- a/layout_paragraphs.module +++ b/layout_paragraphs.module @@ -59,13 +59,13 @@ function layout_paragraphs_theme() { 'variables' => [ 'attributes' => [], 'label' => NULL, - 'edit_url' => NULL, - 'delete_url' => NULL, - 'dialog_options' => NULL, + 'edit_attributes' => [], + 'delete_attributes' => [], ], ], 'layout_paragraphs_builder_component_menu' => [ 'variables' => [ + 'attributes' => [], 'types' => NULL, ], ], diff --git a/layout_paragraphs.routing.yml b/layout_paragraphs.routing.yml index 3fd64783dfb1c89bb502f8c8b117adf6848659e0..8b13518228f135fe74e9c55dd26c7a371d43a0a9 100644 --- a/layout_paragraphs.routing.yml +++ b/layout_paragraphs.routing.yml @@ -25,13 +25,9 @@ layout_paragraphs.builder.formatter: _layout_paragraphs_builder_access: 'TRUE' layout_paragraphs.builder.choose_component: - path: '/layout-paragraphs-builder/{layout_paragraphs_layout}/choose-component/{sibling_uuid}/{placement}/{region}/{parent_uuid}' + path: '/layout-paragraphs-builder/{layout_paragraphs_layout}/choose-component' defaults: - _controller: '\Drupal\layout_paragraphs\Controller\ChooseComponentController::build' - region: 0 - parent_uuid: 0 - sibling_uuid: 0 - placement: 0 + _controller: '\Drupal\layout_paragraphs\Controller\ChooseComponentController::list' options: parameters: layout_paragraphs_layout: @@ -50,36 +46,10 @@ layout_paragraphs.builder.edit_item: requirements: _layout_paragraphs_builder_access: 'TRUE' -layout_paragraphs.builder.insert_sibling: - path: '/layout-paragraphs-builder/{layout_paragraphs_layout}/insert-sibling/{sibling_uuid}/{placement}/{paragraph_type}' - defaults: - _form: '\Drupal\layout_paragraphs\Form\InsertComponentSiblingForm' - options: - parameters: - layout_paragraphs_layout: - layout_paragraphs_layout_tempstore: TRUE - paragraph_type: - type: entity:paragraphs_type - requirements: - _layout_paragraphs_builder_access: 'TRUE' - layout_paragraphs.builder.insert: path: '/layout-paragraphs-builder/{layout_paragraphs_layout}/insert-component/{paragraph_type}' defaults: - _form: '\Drupal\layout_paragraphs\Form\InsertComponentForm' - options: - parameters: - layout_paragraphs_layout: - layout_paragraphs_layout_tempstore: TRUE - paragraph_type: - type: entity:paragraphs_type - requirements: - _layout_paragraphs_builder_access: 'TRUE' - -layout_paragraphs.builder.insert_into_region: - path: '/layout-paragraphs-builder/{layout_paragraphs_layout}/insert-into-region/{parent_uuid}/{region}/{paragraph_type}' - defaults: - _form: '\Drupal\layout_paragraphs\Form\InsertComponentForm' + _controller: '\Drupal\layout_paragraphs\Controller\ComponentFormController::insertForm' options: parameters: layout_paragraphs_layout: diff --git a/src/Controller/ChooseComponentController.php b/src/Controller/ChooseComponentController.php index 9ae6a21a7dd340cfbc165d12502c503049d3493d..d5916b37fe2956799586f91ed7d2c1a6da8a2e0e 100644 --- a/src/Controller/ChooseComponentController.php +++ b/src/Controller/ChooseComponentController.php @@ -5,14 +5,15 @@ namespace Drupal\layout_paragraphs\Controller; use Drupal\Core\Url; use Drupal\Core\Template\Attribute; use Drupal\Core\Ajax\AjaxHelperTrait; -use Drupal\Component\Serialization\Json; use Drupal\Core\Controller\ControllerBase; -use Drupal\layout_paragraphs\LayoutParagraphsLayout; use Drupal\Core\Entity\EntityTypeBundleInfoInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Drupal\layout_paragraphs\LayoutParagraphsLayout; use Drupal\layout_paragraphs\LayoutParagraphsLayoutRefreshTrait; use Drupal\layout_paragraphs\Event\LayoutParagraphsAllowedTypesEvent; +use Drupal\layout_paragraphs\DialogHelperTrait; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * ChooseComponentController controller class. @@ -24,13 +25,17 @@ class ChooseComponentController extends ControllerBase { use AjaxHelperTrait; use LayoutParagraphsLayoutRefreshTrait; + use DialogHelperTrait; /** * Settings to pass to jQuery modal dialog. * * @var array */ - protected $dialogOptions; + protected $dialogOptions = [ + 'modal' => TRUE, + 'width' => '70%', + ]; /** * The entity type bundle info service. @@ -57,15 +62,6 @@ class ChooseComponentController extends ControllerBase { public function __construct(EntityTypeBundleInfoInterface $entity_type_bundle_info, EventDispatcherInterface $event_dispatcher) { $this->entityTypeBundleInfo = $entity_type_bundle_info; $this->eventDispatcher = $event_dispatcher; - $this->dialogOptions = [ - 'width' => '70%', - 'minWidth' => 500, - 'maxWidth' => 1000, - 'draggable' => TRUE, - 'classes' => [ - 'ui-dialog' => 'lpe-dialog', - ], - ]; } /** @@ -81,80 +77,50 @@ class ChooseComponentController extends ControllerBase { /** * Builds the component menu. * + * @param \Symfony\Component\HttpFoundation\Request $request + * The HTTP request. * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout_paragraphs_layout * The layout paragraphs layout object. - * @param string $sibling_uuid - * The uuid of the paragraph to insert content adjacent to. - * @param string $placement - * Whether to insert the new component "before" or "after" the sibling. - * @param string $region - * The region the new component should be inserted into. - * @param string $parent_uuid - * The uuid of the parent component we are inserting into. * * @return array * The build array. */ - public function build( - LayoutParagraphsLayout $layout_paragraphs_layout, - $sibling_uuid = '', - $placement = '', - $region = '', - $parent_uuid = '' - ) { + public function list(Request $request, LayoutParagraphsLayout $layout_paragraphs_layout) { + $route_name = 'layout_paragraphs.builder.insert'; $route_params = [ 'layout_paragraphs_layout' => $layout_paragraphs_layout->id(), ]; - if ($region && $parent_uuid) { - $route_name = 'layout_paragraphs.builder.insert_into_region'; - $route_params += [ - 'parent_uuid' => $parent_uuid, - 'region' => $region, - ]; - } - elseif ($sibling_uuid && $placement) { - $route_name = 'layout_paragraphs.builder.insert_sibling'; - $route_params += [ - 'placement' => $placement, - 'sibling_uuid' => $sibling_uuid, - ]; - $component = $layout_paragraphs_layout->getComponentByUuid($sibling_uuid); - $parent_uuid = $component->getParentUuid(); - $region = $component->getRegion(); - } - else { - $route_name = 'layout_paragraphs.builder.insert'; - } - + $query_params = [ + 'parent_uuid' => $request->query->get('parent_uuid', NULL), + 'region' => $request->query->get('region', NULL), + 'sibling_uuid' => $request->query->get('sibling_uuid', NULL), + 'placement' => $request->query->get('placement', NULL), + ]; + $types = $this->getAllowedComponentTypes($layout_paragraphs_layout, $query_params['parent_uuid'], $query_params['region']); // If there is only one type to render, // return the component form instead of a list of links. - $types = $this->getAllowedComponentTypes($layout_paragraphs_layout, $parent_uuid, $region); if (count($types) === 1) { $type_name = key($types); $type = $this->entityTypeManager()->getStorage('paragraphs_type')->load($type_name); - switch ($route_name) { - case 'layout_paragraphs.builder.insert_into_region': - $response = $this->formBuilder()->getForm('\Drupal\layout_paragraphs\Form\InsertComponentForm', $layout_paragraphs_layout, $type, $parent_uuid, $region); - break; - - case 'layout_paragraphs.builder.insert': - $response = $this->formBuilder()->getForm('\Drupal\layout_paragraphs\Form\InsertComponentForm', $layout_paragraphs_layout, $type); - break; - - case 'layout_paragraphs.builder.insert_sibling': - $response = $this->formBuilder()->getForm('\Drupal\layout_paragraphs\Form\InsertComponentSiblingForm', $layout_paragraphs_layout, $type, $sibling_uuid, $placement); - break; - } + $response = $this->formBuilder->getForm( + '\Drupal\layout_paragraphs\Form\InsertComponentForm', + $layout_paragraphs_layout, + $type, + $query_params['parent_uuid'], + $query_params['region'], + $query_params['sibling_uuid'], + $query_params['placement'] + ); return $response; } foreach ($types as &$type) { - $type['url'] = Url::fromRoute($route_name, $route_params + ['paragraph_type' => $type['id']])->toString(); + $url_route_params = $route_params + ['paragraph_type' => $type['id']]; + $url_options = ['query' => $query_params]; + $type['url'] = Url::fromRoute($route_name, $url_route_params, $url_options)->toString(); $type['link_attributes'] = new Attribute([ 'class' => ['use-ajax'], - 'data-dialog-type' => 'modal', - 'data-dialog-options' => Json::encode($this->dialogOptions), ]); } @@ -167,6 +133,9 @@ class ChooseComponentController extends ControllerBase { $component_menu = [ '#title' => $this->t('Choose a component'), '#theme' => 'layout_paragraphs_builder_component_menu', + '#attributes' => [ + 'class' => ['lpb-component-list'], + ], '#types' => [ 'layout' => $section_components, 'content' => $content_components, diff --git a/src/Controller/ComponentFormController.php b/src/Controller/ComponentFormController.php new file mode 100644 index 0000000000000000000000000000000000000000..06597b09a5830fb5e77708d4013126e862fb3172 --- /dev/null +++ b/src/Controller/ComponentFormController.php @@ -0,0 +1,83 @@ +<?php + +namespace Drupal\layout_paragraphs\Controller; + +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\AjaxHelperTrait; +use Drupal\Core\Ajax\OpenDialogCommand; +use Drupal\Core\Controller\ControllerBase; +use Symfony\Component\HttpFoundation\Request; +use Drupal\paragraphs\ParagraphsTypeInterface; +use Drupal\layout_paragraphs\LayoutParagraphsLayout; +use Drupal\layout_paragraphs\DialogHelperTrait; + +/** + * Class definition for ComponentFormController. + */ +class ComponentFormController extends ControllerBase { + + use AjaxHelperTrait; + use DialogHelperTrait; + + /** + * The options to use for opening the dialog. + * + * @var array + */ + protected $dialogOptions = [ + 'modal' => TRUE, + 'width' => '70%', + 'minWidth' => 500, + 'maxWidth' => 1000, + 'draggable' => TRUE, + 'classes' => [ + 'ui-dialog' => 'lpe-dialog', + ], + ]; + + /** + * Responds with a component insert form. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout_paragraphs_layout + * The layout paragraphs layout object. + * @param \Drupal\paragraphs\ParagraphsTypeInterface $paragraph_type + * The Paragraph Type to insert. + * + * @return array|\Drupal\Core\Ajax\AjaxResponse + * A build array or Ajax respone. + */ + public function insertForm(Request $request, LayoutParagraphsLayout $layout_paragraphs_layout, ParagraphsTypeInterface $paragraph_type) { + + $parent_uuid = $request->query->get('parent_uuid'); + $region = $request->query->get('region'); + $sibling_uuid = $request->query->get('sibling_uuid'); + $placement = $request->query->get('placement'); + + $form = $this->formBuilder()->getForm('\Drupal\layout_paragraphs\Form\InsertComponentForm', $layout_paragraphs_layout, $paragraph_type, $parent_uuid, $region, $sibling_uuid, $placement); + return $this->openForm($form, $layout_paragraphs_layout); + } + + /** + * Returns the form, with ajax if appropriate. + * + * @param array $form + * The form. + * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout_paragraphs_layout + * The layout paragraphs layout object. + * + * @return array|AjaxResponse + * The form or ajax response. + */ + protected function openForm(array $form, LayoutParagraphsLayout $layout_paragraphs_layout) { + if ($this->isAjax()) { + $response = new AjaxResponse(); + $selector = $this->dialogSelector($layout_paragraphs_layout); + $response->addCommand(new OpenDialogCommand($selector, $form['#title'], $form, $this->dialogOptions)); + return $response; + } + return $form; + } + +} diff --git a/src/DialogHelperTrait.php b/src/DialogHelperTrait.php new file mode 100644 index 0000000000000000000000000000000000000000..bad7593f6d027b241811a592b1e173ce510eb0a5 --- /dev/null +++ b/src/DialogHelperTrait.php @@ -0,0 +1,52 @@ +<?php + +namespace Drupal\layout_paragraphs; + +use Drupal\Component\Utility\Html; +use Drupal\Core\Ajax\CloseDialogCommand; + +/** + * Defines a dialog id helper trait. + */ +trait DialogHelperTrait { + + /** + * Generates a dialog id for a given layout. + * + * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout + * The layout paragraphs object. + * + * @return string + * The id. + */ + protected function dialogId(LayoutParagraphsLayout $layout) { + return Html::getId('lpb-dialog-' . $layout->id()); + } + + /** + * Generates a dialog selector for a given layout. + * + * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout + * The layout paragraphs layout object. + * + * @return string + * The dom selector for the dialog. + */ + protected function dialogSelector(LayoutParagraphsLayout $layout) { + return '#' . $this->dialogId($layout); + } + + /** + * Returns a CloseDialogComand with the correct selector. + * + * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout + * The layout paragraphs layout object. + * + * @return \Drupal\Core\Ajax\CommandInterface + * The close command. + */ + protected function closeDialogCommand(LayoutParagraphsLayout $layout) { + return new CloseDialogCommand($this->dialogSelector($layout)); + } + +} diff --git a/src/Element/LayoutParagraphsBuilder.php b/src/Element/LayoutParagraphsBuilder.php index eb1f890fd3e7c7052f633c835717ad23ef4bb9f0..63e9dfd3d8b86b40aa2e65430a7a2f61edf5f93e 100644 --- a/src/Element/LayoutParagraphsBuilder.php +++ b/src/Element/LayoutParagraphsBuilder.php @@ -2,23 +2,25 @@ namespace Drupal\layout_paragraphs\Element; -use Drupal\core\Url; +use Drupal\Component\Serialization\Json; +use Drupal\Core\Url; use Drupal\Core\Render\Markup; use Drupal\Core\Render\Renderer; -use Drupal\Component\Serialization\Json; use Drupal\Core\Access\AccessResultAllowed; -use Drupal\paragraphs\ParagraphInterface; use Drupal\Core\Layout\LayoutPluginManager; use Drupal\Core\Entity\EntityTypeBundleInfo; use Drupal\Core\Access\AccessResultForbidden; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Render\Element\RenderElement; use Drupal\Core\Entity\EntityTypeManagerInterface; -use Drupal\layout_paragraphs\LayoutParagraphsSection; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Template\Attribute; +use Drupal\paragraphs\ParagraphInterface; +use Drupal\layout_paragraphs\LayoutParagraphsSection; use Drupal\layout_paragraphs\LayoutParagraphsComponent; -use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\layout_paragraphs\LayoutParagraphsLayoutTempstoreRepository; +use Drupal\layout_paragraphs\DialogHelperTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Defines a render element for building the Layout Builder UI. @@ -30,6 +32,8 @@ use Drupal\layout_paragraphs\LayoutParagraphsLayoutTempstoreRepository; */ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryPluginInterface { + use DialogHelperTrait; + /** * The layout paragraphs tempstore service. * @@ -100,18 +104,6 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP */ protected $langcode; - /** - * The dialog options. - * - * @var array - */ - protected $dialogOptions = [ - 'width' => 1200, - 'height' => 500, - 'modal' => TRUE, - 'target' => 'lpb-component-menu', - ]; - /** * {@inheritDoc} */ @@ -283,27 +275,52 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP $url_params = [ 'layout_paragraphs_layout' => $this->layoutParagraphsLayout->id(), + ]; + $query_params = [ 'sibling_uuid' => $entity->uuid(), ]; if ($this->editAccess($entity)) { - $edit_url = Url::fromRoute('layout_paragraphs.builder.edit_item', [ - 'layout_paragraphs_layout' => $this->layoutParagraphsLayout->id(), - 'component_uuid' => $entity->uuid(), + $edit_attributes = new Attribute([ + 'href' => Url::fromRoute('layout_paragraphs.builder.edit_item', [ + 'layout_paragraphs_layout' => $this->layoutParagraphsLayout->id(), + 'component_uuid' => $entity->uuid(), + ])->toString(), + 'class' => [ + 'lpb-edit', + 'use-ajax', + ], + 'data-dialog-type' => 'dialog', + 'data-dialog-options' => Json::encode([ + 'width' => '70%', + 'modal' => TRUE, + 'target' => $this->dialogId($this->layoutParagraphsLayout), + ]), ]); } else { - $edit_url = ''; + $edit_attributes = []; } if ($this->deleteAccess($entity)) { - $delete_url = Url::fromRoute('layout_paragraphs.builder.delete_item', [ - 'layout_paragraphs_layout' => $this->layoutParagraphsLayout->id(), - 'component_uuid' => $entity->uuid(), + $delete_attributes = new Attribute([ + 'href' => Url::fromRoute('layout_paragraphs.builder.delete_item', [ + 'layout_paragraphs_layout' => $this->layoutParagraphsLayout->id(), + 'component_uuid' => $entity->uuid(), + ])->toString(), + 'class' => [ + 'lpb-delete', + 'use-ajax', + ], + 'data-dialog-type' => 'dialog', + 'data-dialog-options' => Json::encode([ + 'modal' => TRUE, + 'target' => $this->dialogId($this->layoutParagraphsLayout), + ]), ]); } else { - $delete_url = ''; + $delete_attributes = []; } $build['controls'] = [ @@ -314,9 +331,8 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP ], ], '#label' => $entity->getParagraphType()->label, - '#edit_url' => $edit_url, - '#delete_url' => $delete_url, - '#dialog_options' => Json::encode($this->dialogOptions), + '#edit_attributes' => $edit_attributes, + '#delete_attributes' => $delete_attributes, '#weight' => -10001, ]; if ($component->isLayout()) { @@ -325,12 +341,12 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP if ($this->createAccess()) { if (!$component->getParentUuid() && $this->layoutParagraphsLayout->getSetting('require_layouts')) { - $build['insert_before'] = $this->insertSectionButton($url_params + ['placement' => 'before'], -10000, ['before']); - $build['insert_after'] = $this->insertSectionButton($url_params + ['placement' => 'after'], 10000, ['after']); + $build['insert_before'] = $this->insertSectionButton($url_params, $query_params + ['placement' => 'before'], -10000, ['before']); + $build['insert_after'] = $this->insertSectionButton($url_params, $query_params + ['placement' => 'after'], 10000, ['after']); } else { - $build['insert_before'] = $this->insertComponentButton($url_params + ['placement' => 'before'], -10000, ['before']); - $build['insert_after'] = $this->insertComponentButton($url_params + ['placement' => 'after'], 10000, ['after']); + $build['insert_before'] = $this->insertComponentButton($url_params, $query_params + ['placement' => 'before'], -10000, ['before']); + $build['insert_after'] = $this->insertComponentButton($url_params, $query_params + ['placement' => 'after'], 10000, ['after']); } } @@ -346,6 +362,8 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP foreach ($region_names as $region_name) { $url_params = [ 'layout_paragraphs_layout' => $this->layoutParagraphsLayout->id(), + ]; + $query_params = [ 'parent_uuid' => $entity->uuid(), 'region' => $region_name, ]; @@ -359,7 +377,7 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP ], ]; if ($this->createAccess()) { - $build['regions'][$region_name]['insert_button'] = $this->insertComponentButton($url_params, 10000, ['center']); + $build['regions'][$region_name]['insert_button'] = $this->insertComponentButton($url_params, $query_params, 10000, ['center']); } } } @@ -407,6 +425,8 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP * * @param array[] $route_params * The route parameters for the link. + * @param array[] $query_params + * The query paramaters for the link. * @param int $weight * The weight of the button element. * @param array[] $classes @@ -415,17 +435,20 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP * @return array * The render array. */ - protected function insertComponentButton(array $route_params = [], int $weight = 0, array $classes = []) { + protected function insertComponentButton(array $route_params = [], array $query_params = [], int $weight = 0, array $classes = []) { return [ '#type' => 'link', '#title' => Markup::create('<span class="visually-hidden">' . $this->t('Choose component') . '</span>'), '#weight' => $weight, '#attributes' => [ 'class' => array_merge(['lpb-btn--add', 'use-ajax'], $classes), - 'data-dialog-type' => 'modal', - 'data-dialog-options' => Json::encode($this->dialogOptions), + 'data-dialog-type' => 'dialog', + 'data-dialog-options' => Json::encode([ + 'target' => $this->dialogId($this->layoutParagraphsLayout), + 'modal' => TRUE, + ]), ], - '#url' => Url::fromRoute('layout_paragraphs.builder.choose_component', $route_params), + '#url' => Url::fromRoute('layout_paragraphs.builder.choose_component', $route_params, ['query' => $query_params]), ]; } @@ -434,6 +457,8 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP * * @param array[] $route_params * The route parameters for the link. + * @param array[] $query_params + * The query parameters for the link. * @param int $weight * The weight of the button element. * @param array[] $classes @@ -442,16 +467,29 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP * @return array * The render array. */ - protected function insertSectionButton(array $route_params = [], int $weight = 0, array $classes = []) { + protected function insertSectionButton(array $route_params = [], array $query_params = [], int $weight = 0, array $classes = []) { return [ '#type' => 'link', '#title' => Markup::create($this->t('Add section')), '#attributes' => [ 'class' => array_merge(['lpb-btn', 'use-ajax'], $classes), - 'data-dialog-type' => 'modal', - 'data-dialog-options' => Json::encode($this->dialogOptions), + 'data-dialog-type' => 'dialog', + 'data-dialog-options' => Json::encode([ + 'modal' => TRUE, + 'target' => $this->dialogId($this->layoutParagraphsLayout), + ]), ], - '#url' => Url::fromRoute('layout_paragraphs.builder.choose_component', $route_params), + '#url' => Url::fromRoute('layout_paragraphs.builder.choose_component', $route_params, ['query' => $query_params]), + ]; + } + + /** + * Returns an array of dialog options. + */ + protected function dialogOptions() { + return [ + 'modal' => TRUE, + 'target' => $this->dialogId($this->layoutParagraphsLayout), ]; } diff --git a/src/Form/ComponentFormBase.php b/src/Form/ComponentFormBase.php index a77cff89219eb4928a71e12111d29361059d18c9..4514e48363b406b152bcb2fd80b95dece077aa4e 100644 --- a/src/Form/ComponentFormBase.php +++ b/src/Form/ComponentFormBase.php @@ -11,8 +11,8 @@ use Drupal\field_group\FormatterHelper; use Drupal\Core\Extension\ModuleHandler; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Ajax\AjaxFormHelperTrait; +use Drupal\Core\Ajax\CloseDialogCommand; use Drupal\Core\Layout\LayoutPluginManager; -use Drupal\Core\Ajax\CloseModalDialogCommand; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\EntityRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Drupal\layout_paragraphs\LayoutParagraphsLayoutRefreshTrait; use Drupal\layout_paragraphs\LayoutParagraphsLayoutTempstoreRepository; +use Drupal\layout_paragraphs\DialogHelperTrait; /** * Class LayoutParagraphsComponentFormBase. @@ -30,6 +31,7 @@ abstract class ComponentFormBase extends FormBase { use AjaxFormHelperTrait; use LayoutParagraphsLayoutRefreshTrait; + use DialogHelperTrait; /** * The tempstore service. @@ -369,7 +371,7 @@ abstract class ComponentFormBase extends FormBase { */ public function cancel(array &$form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $response->addCommand(new CloseModalDialogCommand()); + $this->ajaxCloseForm($response); return $response; } @@ -385,6 +387,17 @@ abstract class ComponentFormBase extends FormBase { return AccessResult::allowed(); } + /** + * Closes the form with ajax. + * + * @param \Drupal\Core\Ajax\AjaxResponse $response + * The ajax response. + */ + protected function ajaxCloseForm(AjaxResponse &$response) { + $selector = $this->dialogSelector($this->layoutParagraphsLayout); + $response->addCommand(new CloseDialogCommand($selector)); + } + /** * Renders a single Layout Paragraphs Layout paragraph entity. * diff --git a/src/Form/DeleteComponentForm.php b/src/Form/DeleteComponentForm.php index d90c3896cc99e8f551b3b0ded81f78a9142b98af..11e4811e5b5cd483173d201dcf9fa2ba6eff984d 100644 --- a/src/Form/DeleteComponentForm.php +++ b/src/Form/DeleteComponentForm.php @@ -5,11 +5,12 @@ namespace Drupal\layout_paragraphs\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\RemoveCommand; +use Drupal\Core\Ajax\CloseDialogCommand; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Ajax\CloseModalDialogCommand; +use Drupal\layout_paragraphs\DialogHelperTrait; use Drupal\layout_paragraphs\LayoutParagraphsLayout; -use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\layout_paragraphs\LayoutParagraphsLayoutRefreshTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Class DeleteComponentForm. @@ -17,6 +18,7 @@ use Drupal\layout_paragraphs\LayoutParagraphsLayoutRefreshTrait; class DeleteComponentForm extends FormBase { use LayoutParagraphsLayoutRefreshTrait; + use DialogHelperTrait; /** * The layout paragraphs layout tempstore. @@ -107,7 +109,7 @@ class DeleteComponentForm extends FormBase { */ public function deleteComponent(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $response->addCommand(new CloseModalDialogCommand()); + $response->addCommand(new CloseDialogCommand($this->dialogSelector($this->layoutParagraphsLayout))); if ($this->needsRefresh()) { return $this->refreshLayout($response); @@ -127,7 +129,7 @@ class DeleteComponentForm extends FormBase { */ public function closeForm(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $response->addCommand(new CloseModalDialogCommand()); + $response->addCommand($this->closeDialogCommand($this->layoutParagraphsLayout)); return $response; } diff --git a/src/Form/EditComponentForm.php b/src/Form/EditComponentForm.php index 791ee0d4a0ccbbbea482b2bd2cc8bd669058f64a..a30ecd832f604824acb8e240ec68c6deaf7da0f0 100644 --- a/src/Form/EditComponentForm.php +++ b/src/Form/EditComponentForm.php @@ -3,9 +3,7 @@ namespace Drupal\layout_paragraphs\Form; use Drupal\Core\Ajax\AjaxResponse; -use Drupal\Core\Form\SubformState; use Drupal\Core\Ajax\ReplaceCommand; -use Drupal\Core\Ajax\CloseModalDialogCommand; use Drupal\Core\Form\FormStateInterface; use Drupal\layout_paragraphs\LayoutParagraphsLayout; @@ -63,7 +61,7 @@ class EditComponentForm extends ComponentFormBase { public function successfulAjaxSubmit(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $response->addCommand(new CloseModalDialogCommand()); + $this->ajaxCloseForm($response); if ($this->needsRefresh()) { return $this->refreshLayout($response); } diff --git a/src/Form/InsertComponentForm.php b/src/Form/InsertComponentForm.php index 91a0bb923b770f06dec70e7d17a9f35f00bce67a..c4e926da162c43ec1b70a502fc6096a99bcb028b 100644 --- a/src/Form/InsertComponentForm.php +++ b/src/Form/InsertComponentForm.php @@ -7,7 +7,6 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\AppendCommand; use Drupal\Core\Ajax\BeforeCommand; use Drupal\Core\Ajax\PrependCommand; -use Drupal\Core\Ajax\CloseModalDialogCommand; use Drupal\Core\Form\FormStateInterface; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\paragraphs\ParagraphsTypeInterface; @@ -28,11 +27,13 @@ class InsertComponentForm extends ComponentFormBase { protected $domSelector; /** - * Whether to use "before", "after", or "append.". + * The jQuery insertion method to use for adding the new component. + * + * Must be "before", "after", "prepend", or "append.". * * @var string */ - protected $method; + protected $method = 'prepend'; /** * The uuid of the parent component / paragraph. @@ -48,6 +49,22 @@ class InsertComponentForm extends ComponentFormBase { */ protected $region; + /** + * Where to place the new component in relation to sibling. + * + * @var string + * "before" or "after" + */ + protected $placement; + + /** + * The sibling component's uuid. + * + * @var string + * The sibling component's uuid. + */ + protected $siblingUuid; + /** * {@inheritDoc} * @@ -63,6 +80,10 @@ class InsertComponentForm extends ComponentFormBase { * The parent component's uuid. * @param string $region * The region to insert the new component into. + * @param string $sibling_uuid + * The uuid of the sibling component. + * @param string $placement + * Where to place the new component - either "before" or "after". */ public function buildForm( array $form, @@ -70,17 +91,26 @@ class InsertComponentForm extends ComponentFormBase { LayoutParagraphsLayout $layout_paragraphs_layout = NULL, ParagraphsType $paragraph_type = NULL, string $parent_uuid = NULL, - string $region = NULL + string $region = NULL, + string $sibling_uuid = NULL, + string $placement = NULL ) { $this->setLayoutParagraphsLayout($layout_paragraphs_layout); $this->paragraph = $this->newParagraph($paragraph_type); - $this->method = 'prepend'; + $this->parentUuid = $parent_uuid; $this->region = $region; + $this->siblingUuid = $sibling_uuid; + $this->placement = $placement; + if ($this->parentUuid && $this->region) { $this->domSelector = '[data-region-uuid="' . $parent_uuid . '-' . $region . '"]'; } + elseif ($this->siblingUuid && $this->placement) { + $this->domSelector = '[data-uuid="' . $sibling_uuid . '"]'; + $this->method = $placement; + } else { $this->domSelector = '[data-lpb-id="' . $this->layoutParagraphsLayout->id() . '"]'; } @@ -103,7 +133,7 @@ class InsertComponentForm extends ComponentFormBase { public function successfulAjaxSubmit(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $response->addCommand(new CloseModalDialogCommand()); + $this->ajaxCloseForm($response); if ($this->needsRefresh()) { return $this->refreshLayout($response); } @@ -142,7 +172,16 @@ class InsertComponentForm extends ComponentFormBase { } /** - * Inserts the new component into the layout, using the correct method. + * Inserts the new component into the layout. + * + * Determines the correct method based on provided values. + * + * - If parent uuid and region are provided, new component + * is added to the specified region within the specified parent. + * - If sibling uuid and placement are provided, the new component + * is added before or after the existing sibling. + * - If no parameters are added, the new component is simply added + * to the layout at the root level. * * @return $this */ @@ -150,6 +189,17 @@ class InsertComponentForm extends ComponentFormBase { if ($this->parentUuid && $this->region) { $this->layoutParagraphsLayout->insertIntoRegion($this->parentUuid, $this->region, $this->paragraph); } + elseif ($this->siblingUuid && $this->placement) { + switch ($this->placement) { + case 'before': + $this->layoutParagraphsLayout->insertBeforeComponent($this->siblingUuid, $this->paragraph); + break; + + case 'after': + $this->layoutParagraphsLayout->insertAfterComponent($this->siblingUuid, $this->paragraph); + break; + } + } else { $this->layoutParagraphsLayout->appendComponent($this->paragraph); } diff --git a/src/Form/InsertComponentSiblingForm.php b/src/Form/InsertComponentSiblingForm.php deleted file mode 100644 index 7da5d3bd4f9724d22e198e94b7ec37d1ef2e8633..0000000000000000000000000000000000000000 --- a/src/Form/InsertComponentSiblingForm.php +++ /dev/null @@ -1,83 +0,0 @@ -<?php - -namespace Drupal\layout_paragraphs\Form; - -use Drupal\Core\Form\FormStateInterface; -use Drupal\paragraphs\Entity\ParagraphsType; -use Drupal\layout_paragraphs\LayoutParagraphsLayout; - -/** - * Class InsertComponentSiblingForm. - * - * Builds the form for inserting a sibling component. - */ -class InsertComponentSiblingForm extends InsertComponentForm { - - /** - * Where to place the new component in relation to sibling. - * - * @var string - * "before" or "after" - */ - protected $placement; - - /** - * The sibling component's uuid. - * - * @var string - * The sibling component's uuid. - */ - protected $siblingUuid; - - /** - * {@inheritDoc} - * - * @param array $form - * The form array. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state object. - * @param \Drupal\layout_paragraphs\LayoutParagraphsLayout $layout_paragraphs_layout - * The layout paragraphs layout object. - * @param \Drupal\paragraphs\Entity\ParagraphsType $paragraph_type - * The paragraph type. - * @param string $sibling_uuid - * The uuid of the sibling component. - * @param string $placement - * Where to place the new component - either "before" or "after". - */ - public function buildForm( - array $form, - FormStateInterface $form_state, - LayoutParagraphsLayout $layout_paragraphs_layout = NULL, - ParagraphsType $paragraph_type = NULL, - string $sibling_uuid = NULL, - string $placement = NULL - ) { - - $this->setLayoutParagraphsLayout($layout_paragraphs_layout); - $this->paragraph = $this->newParagraph($paragraph_type); - $this->method = $placement; - $this->domSelector = '[data-uuid="' . $sibling_uuid . '"]'; - $this->placement = $placement; - $this->siblingUuid = $sibling_uuid; - - return $this->buildComponentForm($form, $form_state); - } - - /** - * {@inheritDoc} - */ - protected function insertComponent() { - switch ($this->placement) { - case 'before': - $this->layoutParagraphsLayout->insertBeforeComponent($this->siblingUuid, $this->paragraph); - break; - - case 'after': - $this->layoutParagraphsLayout->insertAfterComponent($this->siblingUuid, $this->paragraph); - break; - } - return $this; - } - -} diff --git a/templates/layout-paragraphs-builder-component-menu.html.twig b/templates/layout-paragraphs-builder-component-menu.html.twig index 75c6eb2f7e70ccb4bc74359c343f4ba85221ccec..c161b46c134ded7bcd07839a0ab82691ed60c6b7 100644 --- a/templates/layout-paragraphs-builder-component-menu.html.twig +++ b/templates/layout-paragraphs-builder-component-menu.html.twig @@ -1,4 +1,4 @@ -<div class="lpb-component-list"> +<div{{ attributes }}> <h4 class="visually-hidden">{{ 'Add Item'|t }}</h4> <div class="lpb-component-list__search"> <input class="lpb-component-list-search-input" type="text" placeholder="Filter items..." /> diff --git a/templates/layout-paragraphs-builder-controls.html.twig b/templates/layout-paragraphs-builder-controls.html.twig index 868168dc1e915b2cb682678ff6cfd8a24931cf57..5f957b0542a26abcde022b67db386b284162fcb3 100644 --- a/templates/layout-paragraphs-builder-controls.html.twig +++ b/templates/layout-paragraphs-builder-controls.html.twig @@ -3,6 +3,6 @@ <span class="lpb-controls-label">{{label}}</span> <a class="lpb-up" href="#move-up"><span>{{ 'Move Up'|t }}</span></a> <a class="lpb-down" href="#move-down"><span>{{ 'Move Down'|t }}</span></a> - {% if edit_url %}<a class="lpb-edit use-ajax" data-dialog-type="modal" data-dialog-options="{{ dialog_options }}" href="{{edit_url}}"><span>{{ 'Edit'|t }}</span></a>{% endif %} - {% if delete_url %}<a class="lpb-delete use-ajax" data-dialog-type="modal" href="{{delete_url}}" data-lpb-confirm="{{ 'Really delete? There is no undo.'|t }}"><span>{{ 'Delete'|t }}</span></a>{% endif %} + {% if edit_attributes %}<a{{ edit_attributes }}><span>{{ 'Edit'|t }}</span></a>{% endif %} + {% if delete_attributes %}<a{{ delete_attributes }}><span>{{ 'Delete'|t }}</span></a>{% endif %} </div>