From ad92bd92bb07144e2fe1699d0dd3b66d3f10dc5c Mon Sep 17 00:00:00 2001 From: Tim Bozeman <5920-boze@users.noreply.drupalcode.org> Date: Mon, 30 Sep 2024 18:00:54 +0000 Subject: [PATCH] Issue #3469286 by tim bozeman: Navigation module integration --- assets/3column.svg | 4 +- assets/block.svg | 1 + assets/cog.svg | 25 +-- assets/columns.svg | 1 + assets/image.svg | 4 +- assets/layout-cursor.svg | 13 ++ assets/layout.svg | 1 + assets/plain-text.svg | 4 +- assets/remove.svg | 16 +- assets/section.svg | 6 +- assets/updown.svg | 24 +-- css/lb-plus/section.css | 4 +- css/lb-plus/sidebar.css | 35 ++-- js/lb-plus.js | 4 +- js/lb-plus/drop-zones.js | 5 +- lb_plus.libraries.yml | 14 +- lb_plus.module | 36 +++- lb_plus.routing.yml | 26 +++ lb_plus.services.yml | 2 +- .../src/Form/UpdateBlockForm.php | 12 +- modules/lb_plus_ooo_mommy/css/tweaks.css | 5 +- .../lb_plus_ooo_mommy.info.yml | 4 + .../lb_plus_ooo_mommy.module | 6 +- .../assets/library.svg | 14 +- .../js/lb-plus-toolbar-plus.js | 27 --- .../lb_plus_toolbar_plus.info.yml | 8 - .../lb_plus_toolbar_plus.libraries.yml | 7 - .../lb_plus_toolbar_plus.module | 27 --- src/Controller/ChangeLayout.php | 2 - src/Controller/EditBlockLayout.php | 2 +- src/Controller/LbPlusUi.php | 76 ++++++++ src/Element/LayoutBuilderPlus.php | 7 +- src/Element/LayoutBuilderPlusUI.php | 18 +- src/EventSubscriber/AdminButtons.php | 9 +- src/EventSubscriber/UiPageWrapper.php | 44 +++++ src/Form/OverridesEntityForm.php | 38 ---- src/Plugin/Tool/LayoutBuilder.php | 50 ----- src/Plugin/Tool/LbPlus.php | 122 ++++++++++++ src/Plugin/Tool/lb-plus.css | 13 ++ .../Plugin/Tool/lb-plus.js | 175 ++++++++++++------ src/SectionStorageHandler.php | 8 +- 41 files changed, 542 insertions(+), 357 deletions(-) create mode 100644 assets/block.svg create mode 100644 assets/columns.svg create mode 100644 assets/layout-cursor.svg create mode 100644 assets/layout.svg delete mode 100644 modules/lb_plus_toolbar_plus/js/lb-plus-toolbar-plus.js delete mode 100644 modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.info.yml delete mode 100644 modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.libraries.yml delete mode 100644 modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.module create mode 100644 src/Controller/LbPlusUi.php create mode 100644 src/EventSubscriber/UiPageWrapper.php delete mode 100644 src/Plugin/Tool/LayoutBuilder.php create mode 100644 src/Plugin/Tool/LbPlus.php create mode 100644 src/Plugin/Tool/lb-plus.css rename js/lb-plus-ui.js => src/Plugin/Tool/lb-plus.js (57%) diff --git a/assets/3column.svg b/assets/3column.svg index e0f0682..bc48d4b 100644 --- a/assets/3column.svg +++ b/assets/3column.svg @@ -3,11 +3,11 @@ <defs> <style> .cls-1 { - fill: #fff; + fill: #4f5661; } </style> </defs> <rect class="cls-1" width="13.3" height="60"/> <rect class="cls-1" x="36.7" width="13.3" height="60"/> <rect class="cls-1" x="18.31" y="0" width="13.3" height="60"/> -</svg> \ No newline at end of file +</svg> diff --git a/assets/block.svg b/assets/block.svg new file mode 100644 index 0000000..2acd261 --- /dev/null +++ b/assets/block.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="#000000" viewBox="0 0 256 256"><path d="M223.68,66.15,135.68,18h0a15.88,15.88,0,0,0-15.36,0l-88,48.17a16,16,0,0,0-8.32,14v95.64a16,16,0,0,0,8.32,14l88,48.17a15.88,15.88,0,0,0,15.36,0l88-48.17a16,16,0,0,0,8.32-14V80.18A16,16,0,0,0,223.68,66.15ZM128,32h0l80.34,44L128,120,47.66,76ZM40,90l80,43.78v85.79L40,175.82Zm96,129.57V133.82L216,90v85.78Z"></path></svg> diff --git a/assets/cog.svg b/assets/cog.svg index 4671f19..e2e4b09 100644 --- a/assets/cog.svg +++ b/assets/cog.svg @@ -1,24 +1 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 59.35 59.12"> - <defs> - <style> - .cls-1, .cls-2 { - fill: #fff; - } - - .cls-2 { - stroke: #fff; - stroke-miterlimit: 10; - } - </style> - </defs> - <path class="cls-1" d="m29.68,20.52c5.01,0,9.09,4.08,9.09,9.09s-4.08,9.09-9.09,9.09-9.09-4.08-9.09-9.09,4.08-9.09,9.09-9.09m0-12c-11.65,0-21.09,9.44-21.09,21.09s9.44,21.09,21.09,21.09,21.09-9.44,21.09-21.09-9.44-21.09-21.09-21.09h0Z"/> - <polygon class="cls-2" points="22.53 9.81 36.88 9.81 33.74 .5 25.76 .5 22.53 9.81"/> - <polygon class="cls-2" points="22.53 49.3 36.88 49.3 33.74 58.62 25.76 58.62 22.53 49.3"/> - <polygon class="cls-2" points="9.81 36.78 9.81 22.43 .5 25.57 .5 33.55 9.81 36.78"/> - <polygon class="cls-2" points="10.69 20.99 20.81 10.81 11.99 6.47 6.36 12.13 10.69 20.99"/> - <polygon class="cls-2" points="10.69 38.34 20.81 48.52 11.99 52.86 6.36 47.2 10.69 38.34"/> - <polygon class="cls-2" points="49.53 36.78 49.53 22.43 58.85 25.57 58.85 33.55 49.53 36.78"/> - <polygon class="cls-2" points="48.72 20.93 38.6 10.75 47.42 6.41 53.05 12.07 48.72 20.93"/> - <polygon class="cls-2" points="48.72 38.28 38.6 48.46 47.42 52.8 53.05 47.14 48.72 38.28"/> -</svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="#ffffff" viewBox="0 0 256 256"><path d="M216,130.16q.06-2.16,0-4.32l14.92-18.64a8,8,0,0,0,1.48-7.06,107.6,107.6,0,0,0-10.88-26.25,8,8,0,0,0-6-3.93l-23.72-2.64q-1.48-1.56-3-3L186,40.54a8,8,0,0,0-3.94-6,107.29,107.29,0,0,0-26.25-10.86,8,8,0,0,0-7.06,1.48L130.16,40Q128,40,125.84,40L107.2,25.11a8,8,0,0,0-7.06-1.48A107.6,107.6,0,0,0,73.89,34.51a8,8,0,0,0-3.93,6L67.32,64.27q-1.56,1.49-3,3L40.54,70a8,8,0,0,0-6,3.94,107.71,107.71,0,0,0-10.87,26.25,8,8,0,0,0,1.49,7.06L40,125.84Q40,128,40,130.16L25.11,148.8a8,8,0,0,0-1.48,7.06,107.6,107.6,0,0,0,10.88,26.25,8,8,0,0,0,6,3.93l23.72,2.64q1.49,1.56,3,3L70,215.46a8,8,0,0,0,3.94,6,107.71,107.71,0,0,0,26.25,10.87,8,8,0,0,0,7.06-1.49L125.84,216q2.16.06,4.32,0l18.64,14.92a8,8,0,0,0,7.06,1.48,107.21,107.21,0,0,0,26.25-10.88,8,8,0,0,0,3.93-6l2.64-23.72q1.56-1.48,3-3L215.46,186a8,8,0,0,0,6-3.94,107.71,107.71,0,0,0,10.87-26.25,8,8,0,0,0-1.49-7.06ZM128,168a40,40,0,1,1,40-40A40,40,0,0,1,128,168Z"></path></svg> diff --git a/assets/columns.svg b/assets/columns.svg new file mode 100644 index 0000000..6c4f762 --- /dev/null +++ b/assets/columns.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="#ffffff" viewBox="0 0 256 256"><path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM112,184H56a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm0-32H56a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm0-32H56a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm0-32H56a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm88,96H144a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm0-32H144a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm0-32H144a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Zm0-32H144a8,8,0,0,1,0-16h56a8,8,0,0,1,0,16Z"></path></svg> diff --git a/assets/image.svg b/assets/image.svg index a8c9475..e973e99 100644 --- a/assets/image.svg +++ b/assets/image.svg @@ -7,7 +7,7 @@ } .cls-1, .cls-2 { - stroke: #fff; + stroke: #4f5661; stroke-miterlimit: 10; stroke-width: 5px; } @@ -21,4 +21,4 @@ <polygon class="cls-1" points="70.02 201.25 149.31 141.96 245.19 201.25 70.02 201.25"/> <polyline class="cls-1" points="142.72 201.25 21.74 201.25 87.84 123.64 142.72 201.25"/> <circle class="cls-1" cx="207.85" cy="92.88" r="22.45"/> -</svg> \ No newline at end of file +</svg> diff --git a/assets/layout-cursor.svg b/assets/layout-cursor.svg new file mode 100644 index 0000000..0d8a04a --- /dev/null +++ b/assets/layout-cursor.svg @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 19.5"> + <defs> + <style> + .cls-1 { + stroke: #fff; + stroke-miterlimit: 10; + stroke-width: .25px; + } + </style> + </defs> + <path class="cls-1" d="M21.12.12H1.88C.91.12.12.91.12,1.88v15.75c0,.97.78,1.75,1.75,1.75h19.25c.97,0,1.75-.78,1.75-1.75V1.88c0-.97-.78-1.75-1.75-1.75ZM1.88,1.88h19.25v4.38H1.88V1.88ZM21.12,17.62h-11.38v-9.62h11.38v9.62Z"/> +</svg> diff --git a/assets/layout.svg b/assets/layout.svg new file mode 100644 index 0000000..f59330a --- /dev/null +++ b/assets/layout.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 256 256"><path fill="currentColor" d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,16V96H40V56ZM40,112H96v88H40Zm176,88H112V112H216v88Z"></path></svg> diff --git a/assets/plain-text.svg b/assets/plain-text.svg index d6e1060..012b99a 100644 --- a/assets/plain-text.svg +++ b/assets/plain-text.svg @@ -4,7 +4,7 @@ <style> .cls-1 { fill: none; - stroke: #fff; + stroke: #4f5661; stroke-miterlimit: 10; stroke-width: 6px; } @@ -15,4 +15,4 @@ <path class="cls-1" d="m6.15,230.5c20.62,0,20.62,19.92,41.25,19.92s20.6-19.97,41.23-19.97,20.62,19.92,41.25,19.92,20.6-19.97,41.23-19.97,20.62,19.92,41.25,19.92,20.6-19.97,41.23-19.97"/> <path class="cls-1" d="m6.15,170.11c20.62,0,20.62,19.92,41.25,19.92s20.6-19.97,41.23-19.97,20.62,19.92,41.25,19.92,20.6-19.97,41.23-19.97,20.62,19.92,41.25,19.92,20.6-19.97,41.23-19.97"/> <path class="cls-1" d="m6.24,112.63c20.62,0,20.62,19.92,41.25,19.92s20.6-19.97,41.23-19.97,20.62,19.92,41.25,19.92,20.6-19.97,41.23-19.97,20.62,19.92,41.25,19.92,20.6-19.97,41.23-19.97"/> -</svg> \ No newline at end of file +</svg> diff --git a/assets/remove.svg b/assets/remove.svg index 6a4eefb..22b2855 100644 --- a/assets/remove.svg +++ b/assets/remove.svg @@ -1,15 +1 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36.86 36.86"> - <defs> - <style> - .cls-1 { - fill: none; - stroke: #fff; - stroke-miterlimit: 10; - stroke-width: 9px; - } - </style> - </defs> - <line class="cls-1" x1="3.18" y1="3.18" x2="33.68" y2="33.68"/> - <line class="cls-1" x1="33.68" y1="3.18" x2="3.18" y2="33.68"/> -</svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="#ffffff" viewBox="0 0 256 256"><path d="M208.49,191.51a12,12,0,0,1-17,17L128,145,64.49,208.49a12,12,0,0,1-17-17L111,128,47.51,64.49a12,12,0,0,1,17-17L128,111l63.51-63.52a12,12,0,0,1,17,17L145,128Z"></path></svg> diff --git a/assets/section.svg b/assets/section.svg index e53476e..759b1a7 100644 --- a/assets/section.svg +++ b/assets/section.svg @@ -4,13 +4,13 @@ <style> .cls-1 { fill: none; - stroke: #fff; + stroke: #323946; stroke-miterlimit: 10; stroke-width: 13px; } .cls-2 { - fill: #fff; + fill: #323946; stroke-width: 0px; } </style> @@ -20,4 +20,4 @@ <polygon class="cls-1" points="242.88 243.25 6.5 243.25 6.5 6.5 130.26 6.5 242.88 6.5 242.88 243.25"/> <rect class="cls-1" x="6.87" y="6.75" width="112.29" height="37.71"/> </g> -</svg> \ No newline at end of file +</svg> diff --git a/assets/updown.svg b/assets/updown.svg index 8395137..3aa58f8 100644 --- a/assets/updown.svg +++ b/assets/updown.svg @@ -1,23 +1 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32.49 58.99"> - <defs> - <style> - .cls-1 { - fill: none; - stroke-width: 11px; - } - - .cls-1, .cls-2 { - stroke: #fff; - stroke-miterlimit: 10; - } - - .cls-2 { - stroke-width: 8px; - } - </style> - </defs> - <polygon class="cls-2" points="9.67 49.69 13.28 53.33 16.92 49.71 9.67 49.69"/> - <line class="cls-1" x1="13.39" y1="11.22" x2="13.21" y2="47.03"/> - <polygon class="cls-2" points="16.97 9.31 13.44 5.66 9.76 9.23 16.97 9.31"/> -</svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="#ffffff" viewBox="0 0 256 256"><path d="M168.49,191.51a12,12,0,0,1,0,17l-32,32a12,12,0,0,1-17,0l-32-32a12,12,0,0,1,17-17L116,203V53L104.49,64.49a12,12,0,1,1-17-17l32-32a12,12,0,0,1,17,0l32,32a12,12,0,0,1-17,17L140,53V203l11.51-11.52A12,12,0,0,1,168.49,191.51Z"></path></svg> diff --git a/css/lb-plus/section.css b/css/lb-plus/section.css index 677668d..e4d804f 100644 --- a/css/lb-plus/section.css +++ b/css/lb-plus/section.css @@ -8,7 +8,7 @@ -webkit-user-select: none; background-color: var(--lb-plus-main-color); font-size: 12px; - z-index: 10; + z-index: 2; } .lb-plus-section-admin a { @@ -21,7 +21,7 @@ .active .lb-plus-section.hover:hover { box-shadow: 0 0 0 10px var(--lb-plus-main-color); - z-index: 10; + z-index: 2; } .active .lb-plus-section.hover:hover .lb-plus-section-admin { diff --git a/css/lb-plus/sidebar.css b/css/lb-plus/sidebar.css index d546db0..88e1ea0 100644 --- a/css/lb-plus/sidebar.css +++ b/css/lb-plus/sidebar.css @@ -1,28 +1,19 @@ -#lb-plus-sidebar { - position: fixed; - right: 0; - top: 80px; - width: 350px; - overflow-y: auto; - background-color: var(--lb-plus-main-color); - z-index: 490; - display: none; - color: white; - font-weight: 600; - margin-bottom: 0; +#lb_plus-left-sidebar { + user-select: none; + overflow-y: scroll; + overflow-x: hidden; } - .draggable-block, .draggable-section { display: grid; - margin: 1em; + margin: 0; grid-template-columns: 1fr 1fr 1fr; align-items: center; column-gap: 1em; -webkit-user-drag: element; user-select: none; -webkit-user-select: none; - padding: .5em; + padding: .25rem; cursor: move; } .draggable-section:hover, @@ -41,6 +32,9 @@ .draggable-block-label { grid-column: span 2; + font-size: var(--admin-toolbar-font-size-info-sm); + font-variation-settings: 'wght' 700; + color: var(--admin-toolbar-color-gray-800); } /* Tab styling */ @@ -52,6 +46,9 @@ } .choose-block-tab { + font-size: var(--admin-toolbar-font-size-heading-md); + color: var(--admin-toolbar-color-gray-900); + font-variation-settings: 'wght' 700; user-select: none; -webkit-user-select: none; cursor: pointer; @@ -64,8 +61,7 @@ } .choose-block-tab.active { - background-color: white; - color: #000; + text-decoration: underline var(--admin-toolbar-color-gray-800) 5px; } #close-add-block-sidebar { @@ -96,6 +92,9 @@ #other-block-content summary { background-color: transparent; + font-size: var(--admin-toolbar-font-size-info-sm); + font-variation-settings: 'wght' 700; + color: var(--admin-toolbar-color-gray-800); } #other-block-content .draggable-block { @@ -103,5 +102,5 @@ } #other-block-content .details-wrapper { - margin: 0 1em; + margin: 0; } diff --git a/js/lb-plus.js b/js/lb-plus.js index 15b2da0..124f49c 100644 --- a/js/lb-plus.js +++ b/js/lb-plus.js @@ -3,7 +3,6 @@ import * as blocks from './lb-plus/blocks.js'; import * as dropZones from './lb-plus/drop-zones.js'; (($, Drupal, once) => { - Drupal.LBPlus = {}; /** @@ -38,5 +37,6 @@ jQuery.fn.LBPlusSetLayoutBuilderInactive = () => { for (const layoutBuilders of document.querySelectorAll('.layout-builder.active')) { layoutBuilders.classList.remove('active'); } - document.getElementById('lb-plus-nested-layout-breadcrumb').style.display = 'block'; + // @todo Re-implement bread crumbs. + // document.getElementById('lb-plus-nested-layout-breadcrumb').style.display = 'block'; }; diff --git a/js/lb-plus/drop-zones.js b/js/lb-plus/drop-zones.js index 061f402..7a0f2e3 100644 --- a/js/lb-plus/drop-zones.js +++ b/js/lb-plus/drop-zones.js @@ -213,7 +213,8 @@ function dropZonesEnterRegion (message, e) { column.insertBefore(dropZoneListener(regionDropZone), column.firstElementChild); } // Add a dropzone after each block. - for (let block of column.children) { + for (let entityWrapper of column.children) { + const block = entityWrapper.hasAttribute('data-toolbar-plus-entity-wrapper') ? entityWrapper.firstElementChild : entityWrapper; if ( // Ensure this is a block. It is tempting to call // column.querySelectorAll('.js-layout-builder-block') here, but we need @@ -227,7 +228,7 @@ function dropZonesEnterRegion (message, e) { ) { regionDropZone = createDropZone(message, 'region').cloneNode(true); regionDropZone.setAttribute('preceding-block-uuid', block.dataset.blockUuid); - column.insertBefore(dropZoneListener(regionDropZone), block.nextSibling); + column.insertBefore(dropZoneListener(regionDropZone), entityWrapper.nextSibling); } } } diff --git a/lb_plus.libraries.yml b/lb_plus.libraries.yml index 1989926..9009a04 100644 --- a/lb_plus.libraries.yml +++ b/lb_plus.libraries.yml @@ -1,8 +1,8 @@ layout_builder: js: - js/lb-plus.js: { attributes: { type: 'module' }} - js/misc/layout-builder.js: {} js/misc/dnd-page-scroll.js: {} + js/misc/layout-builder.js: {} + js/lb-plus.js: { attributes: { type: 'module' }} css: theme: css/lb-plus/section.css: {} @@ -15,15 +15,17 @@ layout_builder: dependencies: - core/drupal.displace - core/drupal.message + - core/drupal.ajax - core/drupal.dialog - - toolbar/toolbar lb_plus_ui: js: - js/lb-plus-ui.js: {} + src/Plugin/Tool/lb-plus.js: { attributes: { type: 'module' }} + css: + theme: + src/Plugin/Tool/lb-plus.css: {} dependencies: - - core/drupal.announce - - core/drupal.debounce + - toolbar_plus/toolbar_plus settings: js: diff --git a/lb_plus.module b/lb_plus.module index 1684af1..9890db0 100644 --- a/lb_plus.module +++ b/lb_plus.module @@ -74,18 +74,16 @@ function lb_plus_page_top(array &$page_top) { * Implements hook_preprocess_HOOK(). */ function lb_plus_preprocess_status_messages(&$variables) { - if (LayoutBuilderPlusUI::LbType() === 'layout_block') { - // Remove the unsaved changes message in nested layout builders. It's annoying. - if (isset($variables['message_list']['warning'])) { - foreach ($variables['message_list']['warning'] as $key => $message) { - if (str_contains($message, 'You have unsaved changes.')) { - unset($variables['message_list']['warning'][$key]); - } - } - if (empty($variables['message_list']['warning'])) { - unset($variables['message_list']['warning']); + // Remove the "Unsaved changes" messages. + if (isset($variables['message_list']['warning'])) { + foreach ($variables['message_list']['warning'] as $key => $message) { + if (str_contains($message, 'You have unsaved changes.')) { + unset($variables['message_list']['warning'][$key]); } } + if (empty($variables['message_list']['warning'])) { + unset($variables['message_list']['warning']); + } } } @@ -169,3 +167,21 @@ function lb_plus_entity_update(EntityInterface $entity) { \Drupal::classResolver(InlineBlockEntityOperations::class)->trackInlineBlockUsage($entity); } } + +/** + * Implements hook_page_attachments(). + */ +function lb_plus_page_attachments(array &$attachments) { + if (!\Drupal::currentUser()->hasPermission('configure any layout')) { + return; + } + + // Don't edit admin pages. + $route = \Drupal::service('current_route_match')->getCurrentRouteMatch()->getRouteObject(); + if (\Drupal::service('router.admin_context')->isAdminRoute($route)) { + return; + } + + $attachments['#cache']['contexts'][] = 'user.permissions'; + $attachments['#attached']['library'][] = 'lb_plus/lb_plus_ui'; +} diff --git a/lb_plus.routing.yml b/lb_plus.routing.yml index b600c5c..b2a70a6 100644 --- a/lb_plus.routing.yml +++ b/lb_plus.routing.yml @@ -200,3 +200,29 @@ lb_plus.js.configure_changed_layout: parameters: section_storage: layout_builder_tempstore: TRUE + +lb_plus.js.enable-ui: + path: '/lb-plus/enable-layout-mode/{section_storage_type}/{section_storage}' + defaults: + _title: 'Layout Builder' + _controller: '\Drupal\lb_plus\Controller\LbPlusUi::enabledLayoutMode' + requirements: + _layout_builder_access: 'view' + options: + _admin_route: TRUE + parameters: + section_storage: + layout_builder_tempstore: TRUE + +lb_plus.js.disable-ui: + path: 'lb-plus/disable-layout-mode/{section_storage_type}/{section_storage}/{view_mode}' + defaults: + _title: 'Layout Builder' + _controller: '\Drupal\lb_plus\Controller\LbPlusUi::disableLayoutMode' + requirements: + _layout_builder_access: 'view' + options: + _admin_route: TRUE + parameters: + section_storage: + layout_builder_tempstore: TRUE diff --git a/lb_plus.services.yml b/lb_plus.services.yml index fc9d390..876e6c6 100644 --- a/lb_plus.services.yml +++ b/lb_plus.services.yml @@ -20,7 +20,7 @@ services: class: Drupal\lb_plus\SectionStorageHandler arguments: ['@block_content.uuid_lookup', '@entity_type.manager', '@plugin.manager.layout_builder.section_storage', '@layout_builder.tempstore_repository', '@module_handler'] - lb_plus.event_subscriber: + lb_plus.block_component_render_array: class: Drupal\lb_plus\EventSubscriber\BlockComponentRenderArray arguments: ['@lb_plus.section_storage_handler'] tags: diff --git a/modules/lb_plus_edit_plus/src/Form/UpdateBlockForm.php b/modules/lb_plus_edit_plus/src/Form/UpdateBlockForm.php index 512622b..946079b 100644 --- a/modules/lb_plus_edit_plus/src/Form/UpdateBlockForm.php +++ b/modules/lb_plus_edit_plus/src/Form/UpdateBlockForm.php @@ -6,6 +6,7 @@ use Drupal\Core\Cache\Cache; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Form\SubformState; use Drupal\lb_plus\LbPlusFormTrait; +use Drupal\Core\Ajax\InvokeCommand; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\layout_builder\SectionStorageInterface; @@ -56,8 +57,6 @@ class UpdateBlockForm extends UpdateBlockFormBase { $storage['main_section_storage'] = $main_section_storage; $form_state->setStorage($storage); - - $this->messenger()->addWarning($this->t('You have unsaved changes.')); $form_state->setRebuild(TRUE); // Clear the page cache. @@ -73,12 +72,15 @@ class UpdateBlockForm extends UpdateBlockFormBase { protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state) { $response = new AjaxResponse(); - $entity = $this->getMainEntity($form, $form_state); - $this->buildBottomBar($entity, $response); $this->renderMessages($response); - $this->updateForm($response, $form, $form_state); $this->updatePage($response, $form, $form_state); + // Check if a field was just emptied. + if (!empty($form_state->getUserInput()['settings']['block_form']['empty_field'])) { + $this->updateForm($response, $form, $form_state); + } + $response->addCommand(new InvokeCommand(NULL, 'editPlusIsDoneUpdating')); + return $response; } diff --git a/modules/lb_plus_ooo_mommy/css/tweaks.css b/modules/lb_plus_ooo_mommy/css/tweaks.css index 1ad2889..5f27ff8 100644 --- a/modules/lb_plus_ooo_mommy/css/tweaks.css +++ b/modules/lb_plus_ooo_mommy/css/tweaks.css @@ -1,6 +1,7 @@ /* Reveal the hidden media block context menu and hide the entity edit menu */ -.field--name-field-media article .contextual { - display: none; +/* @todo find a better way to do this. */ +article.media .contextual { + display: none !important; } #layout-builder { diff --git a/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.info.yml b/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.info.yml index 61e820e..cf5f563 100644 --- a/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.info.yml +++ b/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.info.yml @@ -8,3 +8,7 @@ dependencies: - lb_plus_edit_plus:lb_plus_edit_plus - edit_plus_lb:edit_plus_lb - field_sample_value:field_sample_value + - toolbar_plus:toolbar_plus + - edit_plus_lb:edit_plus_lb + - drupal:navigation + - drupal:navigation_top_bar diff --git a/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.module b/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.module index f1bbc1d..95c9575 100644 --- a/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.module +++ b/modules/lb_plus_ooo_mommy/lb_plus_ooo_mommy.module @@ -6,8 +6,8 @@ */ /** - * Implements hook_form_BASE_FORM_ID_alter(). + * Implements hook_page_attachments_alter(). */ -function lb_plus_ooo_mommy_form_node_layout_builder_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { - $form['#attached']['library'][] = 'lb_plus_ooo_mommy/tweaks'; +function lb_plus_ooo_mommy_page_attachments_alter(array &$attachments) { + $attachments['#attached']['library'][] = 'lb_plus_ooo_mommy/tweaks'; } diff --git a/modules/lb_plus_section_library/assets/library.svg b/modules/lb_plus_section_library/assets/library.svg index dfce88a..ed95e65 100644 --- a/modules/lb_plus_section_library/assets/library.svg +++ b/modules/lb_plus_section_library/assets/library.svg @@ -1,13 +1 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58.79 59.65"> - <defs> - <style> - .cls-1 { - fill: #fff; - } - </style> - </defs> - <path class="cls-1" d="m32.57.14l-16.1-.14.06,59.65h16.16s-.12-59.51-.12-59.51Zm-12.38,2.94h8.84v8.2h-8.84s0-8.2,0-8.2Zm0,45.46h8.84v8.27h-8.84v-8.27"/> - <path class="cls-1" d="m0,5.72v53.71h14.38V5.72H0Zm11.92,37.22H2.61v-20.67h9.31v20.67Z"/> - <path class="cls-1" d="m34.14,15.72l10.68,43.62,13.97-3.42-10.68-43.62-13.97,3.42Zm18.98,27.39l-9.05,2.22-4.11-16.79,9.05-2.22,4.11,16.79Z"/> -</svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="#ffffff" viewBox="0 0 256 256"><path d="M231.65,194.55,198.46,36.75a16,16,0,0,0-19-12.39L132.65,34.42a16.08,16.08,0,0,0-12.3,19l33.19,157.8A16,16,0,0,0,169.16,224a16.25,16.25,0,0,0,3.38-.36l46.81-10.06A16.09,16.09,0,0,0,231.65,194.55ZM136,50.15c0-.06,0-.09,0-.09l46.8-10,3.33,15.87L139.33,66Zm10,47.38-3.35-15.9,46.82-10.06,3.34,15.9Zm70,100.41-46.8,10-3.33-15.87L212.67,182,216,197.85C216,197.91,216,197.94,216,197.94ZM104,32H56A16,16,0,0,0,40,48V208a16,16,0,0,0,16,16h48a16,16,0,0,0,16-16V48A16,16,0,0,0,104,32ZM56,48h48V64H56Zm48,160H56V192h48v16Z"></path></svg> diff --git a/modules/lb_plus_toolbar_plus/js/lb-plus-toolbar-plus.js b/modules/lb_plus_toolbar_plus/js/lb-plus-toolbar-plus.js deleted file mode 100644 index abdba04..0000000 --- a/modules/lb_plus_toolbar_plus/js/lb-plus-toolbar-plus.js +++ /dev/null @@ -1,27 +0,0 @@ -(($, Drupal, once) => { - Drupal.behaviors.LBPlusToolbarPlusToggle = { - attach: (context, settings) => { - once('LBPlusToolbarPlusToggle', 'html', context).forEach(element => { - // Toggle Edit+ on and off. - window.addEventListener('toggleToolbarTool', e => { - const pathSegments = window.location.pathname.split('/'); - // Layout Builder + - if ( - e.detail.tool === 'lb_plus' && - e.detail.state === 'on' && - pathSegments.length >= 4 && - pathSegments[3] !== 'layout' && - pathSegments[5] !== 'discard-changes' - ) { - window.location = drupalSettings.LBPlusToolbarPlus.layout; - } else if ( - (e.detail.tool !== 'lb_plus') && - window.location.href.includes(drupalSettings.LBPlusToolbarPlus.layout) - ) { - window.location = drupalSettings.LBPlusToolbarPlus.canonical; - } - }); - }); - } - }; -})(jQuery, Drupal, once); diff --git a/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.info.yml b/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.info.yml deleted file mode 100644 index 5a292d3..0000000 --- a/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.info.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: "Layout Builder + Toolbar +" -description: "Integration with Toolbar +" -type: module -core_version_requirement: ^10 || ^11 -package: 'Page Building' -dependencies: - - lb_plus:lb_plus - - toolbar_plus:toolbar_plus diff --git a/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.libraries.yml b/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.libraries.yml deleted file mode 100644 index 53cafee..0000000 --- a/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.libraries.yml +++ /dev/null @@ -1,7 +0,0 @@ -toolbar_plus: - js: - js/lb-plus-toolbar-plus.js: {} -# dependencies: -# - lb_plus/lb_plus -# - edit_plus/library # @todo include dependencies. - diff --git a/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.module b/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.module deleted file mode 100644 index 154ffe0..0000000 --- a/modules/lb_plus_toolbar_plus/lb_plus_toolbar_plus.module +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -use Drupal\Core\Url; -use Drupal\lb_plus\Element\LayoutBuilderPlusUI; - -/** - * Implements hook_page_bottom(). - */ -function lb_plus_toolbar_plus_page_bottom(array &$page_bottom) { - // @todo make this work with any type of entity. - $node = \Drupal::routeMatch()->getParameter('node'); - if (empty($node)) { - return; - } - // @todo Why doesn't his URL work? -// $layout_url = new Url('layout_builder.overrides.node.view', ['node' => $node]); -// $string = $layout_url->toString(); - $page_bottom['lb_plus_toolbar_plus']['#attached'] = [ - 'library' => ['lb_plus_toolbar_plus/toolbar_plus'], - 'drupalSettings' => [ - 'LBPlusToolbarPlus' => [ - 'canonical' => $node->toUrl('canonical')->toString(), - 'layout' => "/node/{$node->id()}/layout", - ], - ], - ]; -} diff --git a/src/Controller/ChangeLayout.php b/src/Controller/ChangeLayout.php index e6b1a0a..ee86b34 100644 --- a/src/Controller/ChangeLayout.php +++ b/src/Controller/ChangeLayout.php @@ -146,8 +146,6 @@ class ChangeLayout implements ContainerInjectionInterface { $response = $this->rebuildLayout($section_storage, $nested_storage_path); $response->addCommand(new CloseDialogCommand('.ui-dialog-content')); - $uuid = $new_section->getThirdPartySetting('lb_plus', 'uuid'); - $response->addCommand(new InvokeCommand('', 'LBPlusConfigureSection', [$uuid])); return $response; } diff --git a/src/Controller/EditBlockLayout.php b/src/Controller/EditBlockLayout.php index c983a20..d060370 100644 --- a/src/Controller/EditBlockLayout.php +++ b/src/Controller/EditBlockLayout.php @@ -70,7 +70,7 @@ class EditBlockLayout extends ControllerBase { // Update the LB+ UI. $page_bottom = []; \Drupal::classResolver(LayoutBuilderPlusUI::class)->build($page_bottom); - $response->addCommand(new ReplaceCommand('#lb-plus-sidebar-wrapper', $page_bottom)); + $response->addCommand(new ReplaceCommand('#lb_plus-left-sidebar', $page_bottom)); // Set the nested LB UI as active. $response->addCommand(new SettingsCommand(['LB+' => ['active' => $current_layout_block_uuid]], TRUE)); diff --git a/src/Controller/LbPlusUi.php b/src/Controller/LbPlusUi.php new file mode 100644 index 0000000..7206a4e --- /dev/null +++ b/src/Controller/LbPlusUi.php @@ -0,0 +1,76 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\lb_plus\Controller; + +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\ReplaceCommand; +use Drupal\lb_plus\LbPlusRebuildTrait; +use Drupal\lb_plus\SectionStorageHandler; +use Drupal\Core\Controller\ControllerBase; +use Symfony\Component\HttpFoundation\Request; +use Drupal\lb_plus\Element\LayoutBuilderPlusUI; +use Drupal\layout_builder\SectionStorageInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Returns responses for Layout Builder + routes. + */ +final class LbPlusUi extends ControllerBase { + + use LbPlusRebuildTrait; + + public function __construct( + private readonly SectionStorageHandler $lbPlusSectionStorageHandler, + ) {} + + public static function create(ContainerInterface $container): self { + return new self( + $container->get('lb_plus.section_storage_handler'), + ); + } + + /** + * Builds the response. + */ + public function enabledLayoutMode(Request $request, SectionStorageInterface $section_storage): AjaxResponse { + + $response = new AjaxResponse(); + $layout = [ + '#type' => 'layout_builder_plus', + '#section_storage' => $section_storage, + ]; + $entity = $section_storage->getContextValue('entity'); + $view_mode = $section_storage->getContextValue('view_mode'); + + // @todo Put the entity specific selector in a form some where. + $config_name = sprintf('core.entity_view_display.%s.%s.%s', + $entity->getEntityTypeId(), + $entity->bundle(), + $view_mode + ); + + $entity_specific_selector = $this->config($config_name)->get('third_party_settings.lb_plus.ui_selector') ?? '.node__content'; + $selector = "[data-toolbar-plus-entity-wrapper='{$entity->getEntityTypeId()}::{$entity->id()}::$view_mode::{$entity->bundle()}'] $entity_specific_selector"; + + $response->addCommand(new ReplaceCommand($selector, $layout)); + + // Build the sidebar. + $page_bottom = []; + \Drupal::classResolver(LayoutBuilderPlusUI::class)->build($page_bottom); + $response->addCommand(new ReplaceCommand('#lb_plus-left-sidebar', $page_bottom)); + + return $response; + } + + public function disableLayoutMode(Request $request, SectionStorageInterface $section_storage, string $view_mode): AjaxResponse { + $entity = $section_storage->getContextValue('entity'); + $build = $this->entityTypeManager()->getViewBuilder($entity->getEntityTypeId())->view($entity, $view_mode); + + $response = new AjaxResponse(); + $response->addCommand(new ReplaceCommand("[data-toolbar-plus-entity-wrapper='{$entity->getEntityTypeId()}::{$entity->id()}::$view_mode::{$entity->bundle()}']", $build)); + return $response; + } + +} diff --git a/src/Element/LayoutBuilderPlus.php b/src/Element/LayoutBuilderPlus.php index 77e8d43..685d70c 100644 --- a/src/Element/LayoutBuilderPlus.php +++ b/src/Element/LayoutBuilderPlus.php @@ -6,6 +6,8 @@ use Drupal\Core\Url; use Drupal\Component\Uuid\UuidInterface; use Drupal\Core\Render\Element; use Drupal\Core\Ajax\AjaxHelperTrait; +use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage; +use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage; use Drupal\lb_plus\SectionStorageHandler; use Drupal\lb_plus\Event\AdminButtonsEvent; use Drupal\Core\Render\Element\RenderElement; @@ -88,7 +90,10 @@ class LayoutBuilderPlus extends RenderElement implements ContainerFactoryPluginI if ($element['#section_storage'] instanceof SectionStorageInterface) { $this->sectionStorage = $element['#section_storage']; $this->nestedStoragePath = $element['#nested_storage_path'] ?? NULL; - if ($this->isLayoutBlock()) { + if (!$this->sectionStorage instanceof OverridesSectionStorage && !$this->sectionStorage instanceof DefaultsSectionStorage) { + $layout_builder_type = $this->sectionStorage->getPluginId(); + } + elseif ($this->isLayoutBlock()) { $this->layoutBlockSectionStorage = $this->sectionStorageHandler->getCurrentSectionStorage($this->sectionStorage, $this->nestedStoragePath); $layout_builder_type = 'layout_block'; } diff --git a/src/Element/LayoutBuilderPlusUI.php b/src/Element/LayoutBuilderPlusUI.php index 5adb7ae..89e2c2f 100644 --- a/src/Element/LayoutBuilderPlusUI.php +++ b/src/Element/LayoutBuilderPlusUI.php @@ -64,8 +64,8 @@ class LayoutBuilderPlusUI implements ContainerInjectionInterface { */ public function build(array &$page_top) { $layout_builder_type = self::LbType(); - if (empty($layout_builder_type) || $this->routeMatch->getRouteName() === 'lb_plus.settings') { - // This is not a layout builder page. Don't show the sidebar. + if (!in_array($layout_builder_type, ['layout_block', 'entity']) || $this->routeMatch->getRouteName() === 'lb_plus.settings') { + // This is not a supported layout builder section storage. Don't show the sidebar. return; } $parameters = $this->routeMatch->getParameters(); @@ -79,7 +79,7 @@ class LayoutBuilderPlusUI implements ContainerInjectionInterface { '#attributes' => [ 'id' => 'lb-plus-sidebar-wrapper', 'class' => ["lb-plus-sidebar-$layout_builder_type"], - 'data-offset-right' => '350', +// 'data-offset-left' => '350', ], 'sidebar' => $sidebar, ]; @@ -130,11 +130,21 @@ class LayoutBuilderPlusUI implements ContainerInjectionInterface { $build = [ '#type' => 'container', '#attributes' => [ - 'id' => 'lb-plus-sidebar', + 'id' => 'lb_plus-left-sidebar', + 'class' => ['toolbar-plus-sidebar', 'left-sidebar'], ], '#attached' => ['library' => ['lb_plus/lb_plus_ui']], ]; + // @todo inject + $sidebar_state = \Drupal::request()->cookies->get('lbPlusSidebar') ?? 'closed'; + if ($sidebar_state === 'closed') { + $build['#attributes']['class'][] = 'toolbar-plus-hidden'; + } else { + $build['#attributes']['data-offset-left'] = ''; + } + + // Add a tabbed layout to toggle between promoted blocks and the rest of them. $build['tabs'] = [ '#type' => 'container', diff --git a/src/EventSubscriber/AdminButtons.php b/src/EventSubscriber/AdminButtons.php index e19be64..686c0d3 100644 --- a/src/EventSubscriber/AdminButtons.php +++ b/src/EventSubscriber/AdminButtons.php @@ -81,6 +81,13 @@ class AdminButtons implements EventSubscriberInterface { 'attributes' => [ 'class' => ['use-ajax'], 'data-dialog-type' => 'dialog', + 'data-dialog-options' => Json::encode([ + 'width' => 450, + 'height' => 'auto', + 'target' => 'layout-builder-modal', + 'autoResize' => TRUE, + 'modal' => TRUE, + ]), ], ]), '#title' => [ @@ -89,7 +96,7 @@ class AdminButtons implements EventSubscriberInterface { 'title' => $this->t('Layout'), 'class' => ['lb-plus-icon', 'change-layout'], 'style' => [ - 'background-image: url("/' . $path . '/assets/3column.svg");', + 'background-image: url("/' . $path . '/assets/columns.svg");', ], ], ], diff --git a/src/EventSubscriber/UiPageWrapper.php b/src/EventSubscriber/UiPageWrapper.php new file mode 100644 index 0000000..03ab865 --- /dev/null +++ b/src/EventSubscriber/UiPageWrapper.php @@ -0,0 +1,44 @@ +<?php declare(strict_types = 1); + +namespace Drupal\lb_plus\EventSubscriber; + +use Drupal\Core\Render\Markup; +use Drupal\twig_events\Event\TwigRenderTemplateEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +final class UiPageWrapper implements EventSubscriberInterface { + + public function onTwigRenderTemplate(TwigRenderTemplateEvent $event): void { + $variables = $event->getVariables(); + $entity_info = $this->getEntityInfo($variables); + if (!empty($entity_info)) { + // Give the rendered entity an AJAX wrapper so it can be updated as + // changes are made. + $output = $event->getOutput(); + $wrapped_output = sprintf('<div class="lb-plus-ui-wrapper" data-toolbar-plus-entity-wrapper="%s::%s::%s">%s</div>', $entity_info['entity_type'], $entity_info['entity_id'], $entity_info['view_mode'], $output->__toString()); + $event->setOutput(Markup::create($wrapped_output)); + } + } + + + private function getEntityInfo(array $variables) { + if (!empty($variables['elements']['#lb_plus_ui'])) { + // Regular entities. + return $variables['elements']['#lb_plus_ui']; + } elseif (!empty($variables['elements']['content']['#lb_plus_ui'])) { + // Inline blocks. + return $variables['elements']['content']['#lb_plus_ui']; + } + } + + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array { + return [ + TwigRenderTemplateEvent::class => ['onTwigRenderTemplate'], + ]; + } + +} diff --git a/src/Form/OverridesEntityForm.php b/src/Form/OverridesEntityForm.php index 51ed688..33b007e 100644 --- a/src/Form/OverridesEntityForm.php +++ b/src/Form/OverridesEntityForm.php @@ -44,44 +44,6 @@ class OverridesEntityForm implements ContainerInjectionInterface { if (!empty($form['layout_builder_message'])) { unset($form['layout_builder_message']); } - // Style the form actions as a toolbar. - $form['actions']['#attributes']['class'][] = 'lb-plus-toolbar'; - $form['actions']['#attributes']['data-offset-bottom'] = ''; - $form['actions']['nested-layout'] = [ - '#type' => 'container', - '#weight' => 980, - '#attributes' => [ - 'id' => 'lb-plus-nested-layout-breadcrumb', - 'style' => [ - 'display: none;', - ], - ], - 'exit_nested_layout' => [ - '#type' => 'link', - '#title' => $this->t('Exit nested layout'), - '#url' => Url::createFromRequest(\Drupal::request()), - '#attributes' => [ - 'class' => ['button'], - ], - ], - ]; - $form['actions']['toggle_sidebar_button'] = [ - '#type' => 'container', - '#weight' => 999, - '#attributes' => [ - 'title' => t('Toggle sidebar'), - 'id' => 'lb-plus-toggle-sidebar', - ], - 'background' => [ - '#type' => 'container', - '#attributes' => [ - 'class' => ['lb-plus-icon'], - 'style' => [ - 'background-image: url("/' . $this->moduleHandler->getModule('lb_plus')->getPath() . '/assets/plus.svg");', - ], - ], - ], - ]; } } diff --git a/src/Plugin/Tool/LayoutBuilder.php b/src/Plugin/Tool/LayoutBuilder.php deleted file mode 100644 index 9e0733c..0000000 --- a/src/Plugin/Tool/LayoutBuilder.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php - -declare(strict_types=1); - -namespace Drupal\lb_plus\Plugin\Tool; - -use Drupal\toolbar_plus\Attribute\Tool; -use Drupal\toolbar_plus\ToolPluginBase; -use Drupal\Core\Extension\ModuleExtensionList; -use Drupal\Core\StringTranslation\TranslatableMarkup; -use Drupal\Core\Plugin\ContainerFactoryPluginInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Drupal\Core\DependencyInjection\ContainerInjectionInterface; - -/** - * Plugin implementation of the tool. - */ -#[Tool( - id: 'lb_plus', - label: new TranslatableMarkup('Layout Builder'), - -)] -final class LayoutBuilder extends ToolPluginBase { - - /** - * {@inheritdoc} - */ - public function getIconsPath(): array { - $path = $this->extensionList->getPath('lb_plus'); - return [ - 'mouse_icon' => "/$path/assets/layout-builder-mouse.svg", - 'toolbar_icon' => "/$path/assets/layout-builder-toolbar.svg"]; - } - - /** - * {@inheritdoc} - */ - public function subTools(): array { - $path = $this->extensionList->getPath('lb_plus'); - return [ - 'move' => [ - 'id' => 'move', - 'label' => 'Move', - 'mouse_icon' => "/$path/assets/layout-builder-move-mouse.svg", - 'toolbar_icon' => "/$path/assets/layout-builder-move-toolbar.svg", - ], - ]; - } - -} diff --git a/src/Plugin/Tool/LbPlus.php b/src/Plugin/Tool/LbPlus.php new file mode 100644 index 0000000..ccf7222 --- /dev/null +++ b/src/Plugin/Tool/LbPlus.php @@ -0,0 +1,122 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\lb_plus\Plugin\Tool; + +use Drupal\toolbar_plus\Attribute\Tool; +use Drupal\toolbar_plus\ToolPluginBase; +use Drupal\Core\Session\AccountInterface; +use Drupal\Core\Extension\ModuleExtensionList; +use Drupal\Core\Extension\ModuleHandlerInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Plugin implementation of the tool. + */ +#[Tool( + id: 'lb_plus', + label: new TranslatableMarkup('Layout'), + weight: 60, +)] +final class LbPlus extends ToolPluginBase { + + use StringTranslationTrait; + + public function __construct(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, ModuleExtensionList $extensionList, protected ModuleHandlerInterface $moduleHandler, protected AccountInterface $currentUser) { + parent::__construct($container, $configuration, $plugin_id, $plugin_definition, $extensionList); + } + + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static ( + $container, + $configuration, + $plugin_id, + $plugin_definition, + $container->get('extension.list.module'), + $container->get('module_handler'), + $container->get('current_user'), + ); + } + + /** + * {@inheritdoc} + */ + public function buildTopBar(): array { + $top_bar = []; + + $top_bar['toggle_sidebar_button'] = [ + '#type' => 'container', + '#attributes' => [ + 'id' => 'lb-plus-toggle-sidebar', + 'title' => $this->t('Drag a block from the sidebar and place it in a drop zone on the page'), + 'class' => ['toolbar-button', 'toolbar-button--collapsible', 'toolbar-button--icon--block'], + ], + 'label' => [ + '#type' => 'html_tag', + '#tag' => 'span', + '#value' => $this->t('Place a new block'), + '#attributes' => ['class' => ['toolbar-button__label']], + ], + ]; + + $top_bar['toggle-preview'] = [ + '#type' => 'container', + '#attributes' => [ + 'id' => 'toolbar-plus-toggle-preview', + 'title' => $this->t('Toggle the content placeholders'), + 'class' => ['toolbar-button', 'toolbar-button--collapsible', 'js-show'], + ], + 'label' => [ + '#id' => 'layout-builder-content-preview', + '#title' => $this->t('Toggle preview'), + '#type' => 'checkbox', + '#attributes' => [ + 'data-content-preview-id' => "Drupal.layout_builder.content_preview.{$this->currentUser->id()}", + 'checked' => 'checked', + ], + '#label_attributes' => ['class' => ['toolbar-button__label']] + ], + ]; + + // @todo inject + $sidebar_state = \Drupal::request()->cookies->get('lbPlusSidebar') ?? 'closed'; + if ($sidebar_state === 'open') { + $top_bar['toggle_sidebar_button']['#attributes']['class'][] = 'active'; + } + + return $top_bar; + } + + /** + * {@inheritdoc} + */ + public function buildLeftSideBar(): array { + return [ + // The sidebar is built in an AJAX call in LayoutBuilderPlusUi. We just + // need the wrapper to render. + '#type' => 'container', + '#attributes' => [ + 'id' => 'lb-plus-sidebar-placeholder', + ], + ]; + } + + /** + * {@inheritdoc} + */ + public function getIconsPath(): array { + $path = $this->extensionList->getPath('lb_plus'); + return [ + 'mouse_icon' => "/$path/assets/layout-builder-mouse.svg", + 'toolbar_button_icons' => [ + 'lb_plus' => "/$path/assets/layout.svg", + 'block' => "/$path/assets/block.svg", + ], + ]; + + } + +} diff --git a/src/Plugin/Tool/lb-plus.css b/src/Plugin/Tool/lb-plus.css new file mode 100644 index 0000000..ad25e05 --- /dev/null +++ b/src/Plugin/Tool/lb-plus.css @@ -0,0 +1,13 @@ +#lb_plus-top-bar { + justify-self: end; +} + +#toolbar-plus-toggle-preview .form-item { + margin: 0; + align-items: center; + label { + margin-left: .5rem; + font-size: var(--admin-toolbar-font-size-info-sm); + color: var(--admin-toolbar-color-gray-800); + } +} diff --git a/js/lb-plus-ui.js b/src/Plugin/Tool/lb-plus.js similarity index 57% rename from js/lb-plus-ui.js rename to src/Plugin/Tool/lb-plus.js index 5a381b2..c435c4d 100644 --- a/js/lb-plus-ui.js +++ b/src/Plugin/Tool/lb-plus.js @@ -1,41 +1,112 @@ -(($, Drupal, once) => { +import * as toolPluginBase from '../../../../toolbar_plus/js/toolbar_plus/tool-plugin-base.js'; - Drupal.behaviors.LBPlusToolbarAndSideBarOffsets = { - attach: (context, settings) => { - $(document).on(`drupalViewportOffsetChange`, (e) => { - // Set how far left the toolbar can go. - for (const toolbar of document.getElementsByClassName('lb-plus-toolbar')) { - toolbar.style.left = Drupal.displace.calculateOffset('left') + 'px'; - } - // Set the upper and lower boundaries for the sidebar. - const sideBar = document.getElementById('lb-plus-sidebar'); - sideBar.style.top = Drupal.displace.calculateOffset('top') + 'px'; - sideBar.style.bottom = Drupal.displace.calculateOffset('bottom') + 'px'; +(($, Drupal, once, displace) => { + + Drupal.LBPlusUi = {}; + + /** + * Toolbar+ plugin + */ + class LbPlusPlugin extends toolPluginBase.ToolPluginBase { + id = 'lb_plus'; + enable = () => { + super.enable(); + Drupal.LBPlusUi.getLayoutBuilder(); + }; + disable = () => { + const ignoredPromise = super.disable(); + Drupal.behaviors.LBPlusToggleSidebar.closeSideBar() + return new Promise((resolve, reject) => { + Drupal.LBPlusUi.getRenderedPage(resolve, reject); }); + }; + } + Drupal.ToolbarPlus.PluginManager.registerPlugin(new LbPlusPlugin()); + + /** + * Get rendered page. + * + * Disable layout builder mode callback. + * + * @param resolve + * @param reject + */ + Drupal.LBPlusUi.getRenderedPage = (resolve, reject) => { + const layoutBuilderElement = document.querySelector('#layout-builder'); + if (!layoutBuilderElement) { + resolve(); + return; } - }; + const parts = layoutBuilderElement.closest('.toolbar-plus-entity-wrapper').dataset.toolbarPlusEntityWrapper.split('::'); + + let ajax = Drupal.ajax({ + url: Drupal.url('lb-plus/disable-layout-mode/overrides/' + parts[0] + '.' + parts[1] + '/' + parts[2]), + type: 'POST', + dataType: 'text', + // submit: EditableElement.info, + progress: { + type: 'fullscreen', + message: Drupal.t('Loading Layout Builder...') + }, + error: error => { + console.error(error.responseText); + // reject(error); + }, + success: (response, status) => { + Promise.resolve( + Drupal.Ajax.prototype.success.call(ajax, response, status) + ).then(() => { + resolve(); + }).catch((e) => { + reject(e.responseText); + }); + } + }); + ajax.execute(); + } + + /** + * Get layout builder. + * + * Enable layout builder mode callback. + */ + Drupal.LBPlusUi.getLayoutBuilder = () => { + // @todo what if there are two entityWrappers on the page? + const parts = document.querySelector('.toolbar-plus-entity-wrapper.layout-builder-entity-wrapper').dataset.toolbarPlusEntityWrapper.split('::'); + + let ajax = Drupal.ajax({ + url: Drupal.url('lb-plus/enable-layout-mode/overrides/' + parts[0] + '.' + parts[1]), + type: 'POST', + dataType: 'text', + progress: { + type: 'fullscreen', + message: Drupal.t('Loading Layout Builder...') + }, + error: error => { + console.error(error.responseText); + }, + success: (response, status) => { + Promise.resolve( + Drupal.Ajax.prototype.success.call(ajax, response, status) + ).then(() => { + displace(true); + }); + } + }); + ajax.execute(); + } Drupal.behaviors.LBPlusToggleSidebar = { attach: (context, settings) => { - // Toggle the sidebar on page load or when the sidebar contents change. - once('LBPlusToggleSidebar', '#lb-plus-sidebar', context).forEach(toggleButton => { - // Persist the current state through page loads. - let sideBarState = localStorage.getItem('LBPlusSideBarState') - if (sideBarState && sideBarState === 'block') { - Drupal.behaviors.LBPlusToggleSidebar.openSidebar(); - } else { - Drupal.behaviors.LBPlusToggleSidebar.closeSidebar(); - } - }); + // Toggle the sidebar on and off when clicked. once('LBPlusToggleSidebar', '#lb-plus-toggle-sidebar', context).forEach(toggleButton => { - // Toggle the sidebar on and off when clicked. toggleButton.onclick = e => { - const sideBar = document.getElementById('lb-plus-sidebar'); - if (sideBar.style.display === 'none' || sideBar.style.display === '') { - Drupal.behaviors.LBPlusToggleSidebar.openSidebar(); + const sideBar = Drupal.behaviors.LBPlusToggleSidebar.getSideBar() + if (sideBar.classList.contains('toolbar-plus-hidden')) { + Drupal.behaviors.LBPlusToggleSidebar.openSideBar(); } else { - Drupal.behaviors.LBPlusToggleSidebar.closeSidebar(); + Drupal.behaviors.LBPlusToggleSidebar.closeSideBar(); } }; }); @@ -43,51 +114,47 @@ // Close sidebar button. once('LBPlusCloseSidebar', '#close-add-block-sidebar', context).forEach(closeButton => { closeButton.onclick = e => { - Drupal.behaviors.LBPlusToggleSidebar.closeSidebar(); + Drupal.behaviors.LBPlusToggleSidebar.closeSideBar(); }; }); // Blank page sidebar button. once('LBPlusBlankPageOpenSidebar', '.blank-page-wrapper', context).forEach(blankPageButton => { - Drupal.behaviors.LBPlusToggleSidebar.openSidebar(); + Drupal.behaviors.LBPlusToggleSidebar.openSideBar(); blankPageButton.onclick = e => { - Drupal.behaviors.LBPlusToggleSidebar.openSidebar(); + Drupal.behaviors.LBPlusToggleSidebar.openSideBar(); }; }); // Close the sidebar when an offcanvas dialog opens. $(window).on('dialog:aftercreate', (event, dialog, $element) => { if ($element.length && $element[0].id === 'drupal-off-canvas') { - Drupal.behaviors.LBPlusToggleSidebar.closeSidebar(); + Drupal.behaviors.LBPlusToggleSidebar.closeSideBar(); } }); }, - openSidebar: () => { - const wrapper = document.getElementById('toolbar-plus-sidebar'); - wrapper.style.display = 'block'; - const sideBar = document.getElementById('lb-plus-sidebar'); - // Position the sidebar between any other fixed thingies. - wrapper.style.top = Drupal.displace.calculateOffset('top') + 'px'; - wrapper.style.bottom = Drupal.displace.calculateOffset('bottom') + 'px'; + openSideBar: () => { // Open the sidebar, remember the state, and set the toggle button rotation. - sideBar.style.display = 'block'; + const sidebar = Drupal.behaviors.LBPlusToggleSidebar.getSideBar(); + sidebar.classList.remove('toolbar-plus-hidden'); + sidebar.setAttribute('data-offset-left', ''); + displace(); localStorage.setItem('LBPlusSideBarState', 'block') - const toggleSideBarIcon = document.getElementById('lb-plus-toggle-sidebar'); - toggleSideBarIcon.classList.add('spin-move'); - // Move the page content over a bit. - document.getElementsByClassName('dialog-off-canvas-main-canvas')[0].style.paddingRight = Drupal.displace.calculateOffset('right') + 'px'; + document.cookie="lbPlusSidebar=open; path=/"; + document.getElementById('lb-plus-toggle-sidebar').classList.add('active'); }, - closeSidebar: () => { - const wrapper = document.getElementById('toolbar-plus-sidebar'); - wrapper.style.display = 'none'; - const sideBar = document.getElementById('lb-plus-sidebar'); + closeSideBar: () => { // Close the sidebar, remember the state, and set the toggle button rotation. - sideBar.style.display = 'none' + const sidebar = Drupal.behaviors.LBPlusToggleSidebar.getSideBar(); + sidebar.classList.add('toolbar-plus-hidden'); + sidebar.removeAttribute('data-offset-left'); + displace(); localStorage.setItem('LBPlusSideBarState', 'none'); - const toggleSideBarIcon = document.getElementById('lb-plus-toggle-sidebar'); - toggleSideBarIcon.classList.remove('spin-move'); - // Move the page content back in place. - document.getElementsByClassName('dialog-off-canvas-main-canvas')[0].style.paddingRight = null; + document.cookie="lbPlusSidebar=closed; path=/"; + document.getElementById('lb-plus-toggle-sidebar').classList.remove('active'); + }, + getSideBar: () => { + return document.getElementById('lb_plus-left-sidebar'); }, }; @@ -210,4 +277,4 @@ ).on('input', Drupal.debounce(filterBlockList, 200)); }, }; -})(jQuery, Drupal, once); +})(jQuery, Drupal, once, Drupal.displace); diff --git a/src/SectionStorageHandler.php b/src/SectionStorageHandler.php index 1767be1..e26af81 100644 --- a/src/SectionStorageHandler.php +++ b/src/SectionStorageHandler.php @@ -176,8 +176,12 @@ class SectionStorageHandler { } while (!empty($nested_storage_pieces)); } - if ($this->moduleHandler->moduleExists('edit_plus') && $entity = $section_storage->getContextValue('entity')) { - Cache::invalidateTags([getCacheTag($entity)]); + if ($this->moduleHandler->moduleExists('edit_plus')) { + $contexts = $section_storage->getContexts(); + if (!empty($contexts['entity'])) { + $entity = $section_storage->getContextValue('entity'); + Cache::invalidateTags([getCacheTag($entity)]); + } } $this->layoutBuilderTempstore->set($section_storage); -- GitLab