From 8616399fe8c3497e4cee16608d74d919bed03b8c Mon Sep 17 00:00:00 2001 From: "Robin Lejeune (role)" Date: Thu, 30 Jan 2025 15:29:42 +0100 Subject: [PATCH] add initial dropzone + use closest dropzone + cancel drop in sidebar --- .../src/builder_sidebar/builder_sidebar.js | 2 + .../tabs/block_tab/block_tab.js | 3 + .../src/plugins/drop_zone_plugin.inside.scss | 69 ++++++++++++------- .../static/src/plugins/drop_zone_plugin.js | 63 ++++++++++++++--- 4 files changed, 101 insertions(+), 36 deletions(-) diff --git a/addons/html_builder/static/src/builder_sidebar/builder_sidebar.js b/addons/html_builder/static/src/builder_sidebar/builder_sidebar.js index 7276b0d1d2af3..541b95aaf8ce9 100644 --- a/addons/html_builder/static/src/builder_sidebar/builder_sidebar.js +++ b/addons/html_builder/static/src/builder_sidebar/builder_sidebar.js @@ -195,6 +195,7 @@ export class BuilderSidebar extends Component { }); onMounted(() => { + this.editor.shared.dropzone.displayInitialDropZone(); // TODO: onload editor this.updateInvisibleEls(); }); @@ -257,6 +258,7 @@ export class BuilderSidebar extends Component { undo() { this.editor.shared.history.undo(); + this.editor.shared.dropzone.clearDropZone(); } redo() { diff --git a/addons/html_builder/static/src/builder_sidebar/tabs/block_tab/block_tab.js b/addons/html_builder/static/src/builder_sidebar/tabs/block_tab/block_tab.js index c813bcb1df95d..107968af1f1d2 100644 --- a/addons/html_builder/static/src/builder_sidebar/tabs/block_tab/block_tab.js +++ b/addons/html_builder/static/src/builder_sidebar/tabs/block_tab/block_tab.js @@ -91,6 +91,9 @@ export class BlockTab extends Component { this.dropzonePlugin.displayDropZone(snippet); } const addElement = this.dropzonePlugin.getAddElement(position); + if (addElement.noDrop) { + return; + } this.dialog.add( AddSnippetDialog, { diff --git a/addons/html_builder/static/src/plugins/drop_zone_plugin.inside.scss b/addons/html_builder/static/src/plugins/drop_zone_plugin.inside.scss index fdd8f32911025..0c7f44c01c26a 100644 --- a/addons/html_builder/static/src/plugins/drop_zone_plugin.inside.scss +++ b/addons/html_builder/static/src/plugins/drop_zone_plugin.inside.scss @@ -1,34 +1,51 @@ -.oe_drop_zone { - height: 10px; - background: $o-we-dropzone-bg-color; - animation: dropZoneInsert 1s linear 0s infinite alternate; - z-index: 2000; +.odoo-editor-editable { + #wrap[data-editor-message]:empty { + $-margin-inline: 2%; + height: 100%; + width: 100% - 2 * $-margin-inline; + padding: 112px 0; + margin: 20px $-margin-inline; - &.oe_insert { - position: relative; - width: 100%; - border-radius: $border-radius-lg; - outline: $o-we-dropzone-border-width dashed $o-we-dropzone-accent-color; - outline-offset: -$o-we-dropzone-border-width; + &::before { + content: attr(data-editor-message); + display: block; + font-size: 1.5rem; + text-align: center; + } } - &.o_dropzone_highlighted { - filter: brightness(1.5); - transition: 200ms; + + .oe_drop_zone { + height: 10px; + background: $o-we-dropzone-bg-color; + animation: dropZoneInsert 1s linear 0s infinite alternate; + z-index: 2000; + + &.oe_insert { + position: relative; + width: 100%; + border-radius: $border-radius-lg; + outline: $o-we-dropzone-border-width dashed $o-we-dropzone-accent-color; + outline-offset: -$o-we-dropzone-border-width; + } + &.o_dropzone_highlighted { + filter: brightness(1.5); + transition: 200ms; + } } -} -.oe_drop_zone:not(.oe_grid_zone) { - &.oe_insert { - min-width: $o-we-dropzone-size; - height: $o-we-dropzone-size; - min-height: $o-we-dropzone-size; - margin: (-$o-we-dropzone-size/2) 0; - padding: 0; + .oe_drop_zone:not(.oe_grid_zone) { + &.oe_insert { + min-width: $o-we-dropzone-size; + height: $o-we-dropzone-size; + min-height: $o-we-dropzone-size; + margin: (-$o-we-dropzone-size/2) 0; + padding: 0; - &.oe_vertical { - width: $o-we-dropzone-size; - float: left; - margin: 0 (-$o-we-dropzone-size/2); + &.oe_vertical { + width: $o-we-dropzone-size; + float: left; + margin: 0 (-$o-we-dropzone-size/2); + } } } } diff --git a/addons/html_builder/static/src/plugins/drop_zone_plugin.js b/addons/html_builder/static/src/plugins/drop_zone_plugin.js index 1b05b197423ea..53211d7308d1c 100644 --- a/addons/html_builder/static/src/plugins/drop_zone_plugin.js +++ b/addons/html_builder/static/src/plugins/drop_zone_plugin.js @@ -1,10 +1,11 @@ import { Plugin } from "@html_editor/plugin"; import { isBlock } from "@html_editor/utils/blocks"; +import { _t } from "@web/core/l10n/translation"; import { closest, touching } from "@web/core/utils/ui"; function filterFunction(el, exclude) { // TODO add all filter like website - if (exclude && el.matches(exclude)) { + if ((exclude && el.matches(exclude)) || el.matches(".oe_drop_zone")) { return false; } return true; @@ -33,7 +34,13 @@ export function scrollToWindow(element, { behavior, offset } = {}) { export class DropZonePlugin extends Plugin { static id = "dropzone"; static dependencies = ["history"]; - static shared = ["displayDropZone", "dragElement", "clearDropZone", "getAddElement"]; + static shared = [ + "displayDropZone", + "displayInitialDropZone", + "dragElement", + "clearDropZone", + "getAddElement", + ]; resources = { savable_mutation_record_predicates: this.isMutationRecordSavable.bind(this), @@ -89,6 +96,10 @@ export class DropZonePlugin extends Plugin { }; } + get wrapEl() { + return this.document.getElementById("wrap"); + } + displayDropZone(snippet) { this.clearDropZone(); @@ -118,14 +129,29 @@ export class DropZonePlugin extends Plugin { } } + displayInitialDropZone() { + this.wrapEl.dataset.editorMessage = _t("DRAG BUILDING BLOCKS HERE"); + this.wrapEl.classList.add("oe_drop_zone", "oe_insert"); + this.dropZoneElements.push(this.wrapEl); + } + clearDropZone() { if (this.dropZoneElements.length) { for (const el of this.editable.querySelectorAll(".oe_drop_zone")) { - el.remove(); + if (el !== this.wrapEl) { + el.remove(); + } } } this.dropZoneElements = []; + + if (this.wrapEl.matches(":empty")) { + this.displayInitialDropZone(); + } else { + delete this.wrapEl.dataset.editorMessage; + this.wrapEl.classList.remove("oe_drop_zone", "oe_insert"); + } } dragElement(element) { @@ -142,25 +168,42 @@ export class DropZonePlugin extends Plugin { } getAddElement(position) { + const cancel = () => { + this.clearDropZone(); + const fn = () => {}; + fn.noDrop = true; + return fn; + }; + if (position && !touching([this.document.body], position).length) { + return cancel(); + } const dropZone = position - ? closest(touching(this.dropZoneElements, position), position) + ? closest(touching(this.dropZoneElements, position), position) || + closest(this.dropZoneElements, position) : closest(this.dropZoneElements, { x: window.innerWidth / 2, y: window.innerHeight / 2, }); if (!dropZone) { - this.clearDropZone(); - return () => {}; + return cancel(); + } + + let target, insertPosition; + if (dropZone === this.wrapEl) { + insertPosition = "appendChild"; + target = dropZone; + } + if (!target) { + insertPosition = "after"; + target = dropZone.previousSibling; } - let target = dropZone.previousSibling; - let addAfter = true; if (!target) { - addAfter = false; + insertPosition = "before"; target = dropZone.nextSibling; } this.clearDropZone(); return (elementToAdd) => { - addAfter ? target.after(elementToAdd) : target.before(elementToAdd); + target[insertPosition](elementToAdd); scrollToWindow(elementToAdd, { behavior: "smooth", offset: 50 }); this.dependencies.history.addStep(); };