diff --git a/js/builder.js b/js/builder.js index 8c792894abc849a868f39a152080e19731f3d548..534f198a71899ae6ccc769159330d0e8d1983f56 100644 --- a/js/builder.js +++ b/js/builder.js @@ -112,7 +112,10 @@ } else { controls.classList.remove('is-fixed'); } - if (controlsRect.bottom + offsetY > componentRect.bottom) { + if ( + controls.classList.contains('is-fixed') && + controlsRect.bottom + offsetY > componentRect.bottom + ) { controls.classList.add('is-scrolled-past'); } else { controls.classList.remove('is-scrolled-past'); @@ -121,8 +124,9 @@ /** * Removes focus data attributes from all components. + * @param {Event} originalEvent The original event that triggered selection. */ - function unselectComponents() { + function unselectComponents(originalEvent) { selectAll('[data-active="true"]').forEach((element) => { element.removeAttribute('data-active'); }); @@ -132,6 +136,13 @@ selectAll('.is-navigating').forEach((element) => element.classList.remove('is-navigating'), ); + if (activeComponent && activeComponent.closest(`[${idAttr}]`)) { + dispatch(activeComponent, 'lpb-component:blur', { + componentUuid: activeComponent.getAttribute('data-uuid'), + layoutId: activeComponent.closest(`[${idAttr}]`).getAttribute(idAttr), + originalEvent, + }); + } activeComponent = null; setUiElementVisibility(); } @@ -140,8 +151,9 @@ * Adds focus data attributes to a component and all its parents. * * @param {HTMLElement} element The component to focus. + * @param {Event} originalEvent The original event that triggered selection. */ - function selectComponent(element) { + function selectComponent(element, originalEvent = {}) { activeComponent = element; select('.lpb-hover-label')?.remove(); // Add the data-active attribute to the element. @@ -151,6 +163,7 @@ dispatch(element, 'lpb-component:focus', { componentUuid: element.getAttribute('data-uuid'), layoutId: element.closest(`[${idAttr}]`).getAttribute(idAttr), + originalEvent, }); setUiElementVisibility(); setControlsPosition(); @@ -297,9 +310,7 @@ submit: { components: JSON.stringify(order), }, - error: () => { - // Fail silently to prevent console errors. - }, + error: () => {}, }).execute(); }; const reorderComponents = debounce(Drupal.layoutParagraphsUpdateOrder); @@ -625,14 +636,14 @@ ajax, response, ) => { - const { layoutId, componentUuid, eventName } = response; + const { layoutId, componentUuid, eventName, extra } = response; const element = document.querySelector(`[data-uuid="${componentUuid}"]`) || document.querySelector(`[data-lpb-id="${layoutId}"]`); - dispatch(element, `lpb-${eventName}`, { componentUuid, layoutId, + extra, }); }; @@ -753,6 +764,9 @@ * Select the component that was clicked. */ listen(document, 'mouseup', (event) => { + if (event.target.ownerDocument !== document) { + return; + } let element = event.target.closest('.js-lpb-component'); if (element) { while ( @@ -764,9 +778,9 @@ element = element.parentNode.closest('.js-lpb-component'); } } - unselectComponents(); + unselectComponents(event); if (element) { - selectComponent(element); + selectComponent(element, event); } }); @@ -774,9 +788,12 @@ const component = event.target.closest('.js-lpb-ui') ? event.target.closest('.js-lpb-component') : null; + if (component === activeComponent) { + return; + } if (component) { - unselectComponents(); - selectComponent(component); + unselectComponents(event); + selectComponent(component, event); } }); @@ -813,11 +830,11 @@ * Selects a newly inserted or updated component. */ listen( - document, + document.body, ['lpb-component:insert', 'lpb-component:update'], (event) => { - unselectComponents(); - selectComponent(event.target); + unselectComponents(event); + selectComponent(event.target, event); }, ); @@ -826,20 +843,20 @@ */ listen(document, 'keydown', (event) => { if (event.key === 'Escape') { - return unselectComponents(); + return unselectComponents(event); } if ( event.key === 'Enter' && event.target.matches('.js-lpb-component:not([data-active="true"])') ) { - unselectComponents(); - return selectComponent(event.target); + unselectComponents(event); + return selectComponent(event.target, event); } if ( event.key === 'Enter' && event.target.matches('.js-lpb-component[data-active="true"]') ) { - return unselectComponents(); + return unselectComponents(event); } const focused = select('.js-lpb-component[data-active="true"]'); if (!focused) { @@ -871,7 +888,7 @@ * Add is-changed class when a layout is modified. */ listen( - document, + document.body, [ 'lpb-component:insert', 'lpb-component:update', @@ -886,9 +903,13 @@ /** * Reorder component on drop or move. */ - listen(document, ['lpb-component:drop', 'lpb-component:move'], (event) => { - reorderComponents(event.target.closest(`[${idAttr}]`)); - }); + listen( + document.body, + ['lpb-component:drop', 'lpb-component:move'], + (event) => { + reorderComponents(event.target.closest(`[${idAttr}]`)); + }, + ); /** * Click handler for various UI elements. diff --git a/src/Ajax/LayoutParagraphsEventCommand.php b/src/Ajax/LayoutParagraphsEventCommand.php index f4952f6870316ae561391f3624bc7cd79dea92af..a7e25171d8dff45336139de03aba0f66467f5038 100644 --- a/src/Ajax/LayoutParagraphsEventCommand.php +++ b/src/Ajax/LayoutParagraphsEventCommand.php @@ -30,13 +30,19 @@ class LayoutParagraphsEventCommand implements CommandInterface { */ protected $eventName; + /** + * Extra data to pass to the event. + */ + protected $extra; + /** * Constructor. */ - public function __construct($layout, $component_uuid, $event_name) { + public function __construct($layout, $component_uuid, $event_name, $extra = []) { $this->layout = $layout; $this->componentUuid = $component_uuid; $this->eventName = $event_name; + $this->extra = $extra; } /** @@ -51,6 +57,7 @@ class LayoutParagraphsEventCommand implements CommandInterface { 'layoutId' => $this->layout->id(), 'componentUuid' => $this->componentUuid, 'eventName' => $this->eventName, + 'extra' => $this->extra, ]; } diff --git a/src/Form/ComponentFormBase.php b/src/Form/ComponentFormBase.php index 0dbb7b2a7a61b711d0b9524b7912b3ce6b439c11..832b32f00e40c613c53c5bad6eb4e1b0f93352ea 100644 --- a/src/Form/ComponentFormBase.php +++ b/src/Form/ComponentFormBase.php @@ -523,10 +523,14 @@ abstract class ComponentFormBase extends FormBase implements ComponentFormInterf * The paragraph render array. */ protected function renderParagraph(string $uuid) { + $this->layoutParagraphsLayout->setComponent($this->paragraph); return [ '#type' => 'layout_paragraphs_builder', '#layout_paragraphs_layout' => $this->layoutParagraphsLayout, '#uuid' => $uuid, + '#cache' => [ + 'max-age' => 0, + ], ]; }