Geisterstunde

This commit is contained in:
Timo Reichl 2025-04-29 19:23:31 +02:00
parent fac7665f8f
commit 4af1e60f76
6 changed files with 107 additions and 25 deletions

View File

@ -4,10 +4,10 @@
:is="resolvedComponent" :is="resolvedComponent"
v-bind="element.props" v-bind="element.props"
@update-items="updateSchema" @update-items="updateSchema"
@dragover.prevent="onDragOver($event)" @dragover.prevent="onDragOver($event, index)"
@drop="onDrop($event, index)" @drop="onDrop($event, index)"
@dragleave="onDragLeave()" @dragleave="onDragLeave()"
:class="getDropClass" :class="(getDropClass, isGhost)"
/> />
</div> </div>
</template> </template>
@ -43,6 +43,7 @@ const FlexLayoutRenderer = defineAsyncComponent(() =>
"@/modules/process/components/formDesigner/renderer/FlexLayoutRenderer.vue" "@/modules/process/components/formDesigner/renderer/FlexLayoutRenderer.vue"
) )
); );
import { useDragStore } from "@/modules/process/store/formBlockDragStatus";
import { InputTextBlock } from "@/modules/process/models/formDesigner/blocks/InputTextBlock"; import { InputTextBlock } from "@/modules/process/models/formDesigner/blocks/InputTextBlock";
import { ButtonBlock } from "@/modules/process/models/formDesigner/blocks/ButtonBlock"; import { ButtonBlock } from "@/modules/process/models/formDesigner/blocks/ButtonBlock";
@ -64,6 +65,7 @@ export default defineComponent({
data() { data() {
return { return {
dropIndicator: null, dropIndicator: null,
dragOver: false,
}; };
}, },
props: { props: {
@ -108,11 +110,28 @@ export default defineComponent({
return ""; return "";
} }
}, },
isGhost() {
return this.element.ghost ? "ghost" : "";
},
}, },
methods: { methods: {
updateSchema(newItems) { updateSchema(newItems) {
this.$emit("update-schema", newItems); this.$emit("update-schema", newItems);
}, },
addGhost(type, index) {
if (
this.dropIndicator?.position === "right" ||
this.dropIndicator?.position === "below"
) {
index = index + 1;
}
let newElement = this.createElementByType(type);
newElement.ghost = true;
this.dropIndicator = null;
if (newElement) {
this.$emit("insert-item", { index, newElement });
}
},
onDrop(event, index) { onDrop(event, index) {
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
@ -129,7 +148,10 @@ export default defineComponent({
this.$emit("insert-item", { index, newElement }); this.$emit("insert-item", { index, newElement });
} }
}, },
onDragOver(event) { async onDragOver(event, index) {
if (this.element.ghost) {
// do nothing
} else {
event.stopPropagation(); event.stopPropagation();
const bounds = event.currentTarget.getBoundingClientRect(); const bounds = event.currentTarget.getBoundingClientRect();
const offsetX = event.clientX - bounds.left; const offsetX = event.clientX - bounds.left;
@ -146,10 +168,27 @@ export default defineComponent({
: "below"; : "below";
const curElement = this.element; const curElement = this.element;
if (
position !== this.dropIndicator?.position &&
this.dropIndicator?.position
) {
this.dragOver = false;
await this.$emit("remove-ghosts");
console.log("neue Position");
}
this.dropIndicator = { this.dropIndicator = {
type: curElement.type, type: curElement.type,
position, position,
}; };
if (this.dragOver === false) {
const dragStore = useDragStore();
this.addGhost(dragStore.currentDraggedType, index);
}
this.dragOver = true;
}
}, },
onDragLeave() { onDragLeave() {
if ( if (
@ -158,6 +197,8 @@ export default defineComponent({
) { ) {
this.dropIndicator = null; this.dropIndicator = null;
} }
this.dragOver = false;
this.$emit("remove-ghosts");
}, },
createElementByType(type) { createElementByType(type) {
switch (type) { switch (type) {
@ -235,4 +276,8 @@ export default defineComponent({
bottom: 0; bottom: 0;
width: 2px; width: 2px;
} }
.component-container .ghost {
opacity: 0.3;
}
</style> </style>

View File

@ -31,6 +31,7 @@
class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center" class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center"
draggable="true" draggable="true"
@dragstart="startDrag($event, 'InputText')" @dragstart="startDrag($event, 'InputText')"
@dragend="endDrag"
> >
<div <div
class="col d-flex justify-content-xxl-start align-items-xxl-center" class="col d-flex justify-content-xxl-start align-items-xxl-center"
@ -59,6 +60,7 @@
class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center" class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center"
draggable="true" draggable="true"
@dragstart="startDrag($event, 'InputNumber')" @dragstart="startDrag($event, 'InputNumber')"
@dragend="endDrag"
> >
<div <div
class="col d-flex justify-content-xxl-start align-items-xxl-center" class="col d-flex justify-content-xxl-start align-items-xxl-center"
@ -86,6 +88,7 @@
class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center" class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center"
draggable="true" draggable="true"
@dragstart="startDrag($event, 'InputDate')" @dragstart="startDrag($event, 'InputDate')"
@dragend="endDrag"
> >
<div <div
class="col d-flex justify-content-xxl-start align-items-xxl-center" class="col d-flex justify-content-xxl-start align-items-xxl-center"
@ -113,6 +116,7 @@
class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center" class="row ms-0 me-0 d-flex formItem align-items-center justify-content-center"
draggable="true" draggable="true"
@dragstart="startDrag($event, 'Button')" @dragstart="startDrag($event, 'Button')"
@dragend="endDrag"
> >
<div <div
class="col d-flex justify-content-xxl-start align-items-xxl-center" class="col d-flex justify-content-xxl-start align-items-xxl-center"
@ -236,6 +240,7 @@
</template> </template>
<script> <script>
import { useDragStore } from "@/modules/process/store/formBlockDragStatus";
export default { export default {
name: "FormDesignerToolsComponent", name: "FormDesignerToolsComponent",
// Verwendete Komponenten // Verwendete Komponenten
@ -277,9 +282,15 @@ export default {
// Methoden // Methoden
methods: { methods: {
startDrag(event, type) { startDrag(event, type) {
console.log("Dragging:", type); const dragStore = useDragStore();
dragStore.setDraggedType(type);
event.dataTransfer.setData("text/plain", type); // Speichere das Objekt als JSON event.dataTransfer.setData("text/plain", type); // Speichere das Objekt als JSON
}, },
endDrag() {
const dragStore = useDragStore();
dragStore.clearDraggedType();
this.$emit("remove-ghosts");
},
setActive(type) { setActive(type) {
switch (type) { switch (type) {
case "element": case "element":

View File

@ -8,6 +8,7 @@
:direction="direction" :direction="direction"
@update-schema="updateChildItems(key, $event)" @update-schema="updateChildItems(key, $event)"
@insert-item="insertItem" @insert-item="insertItem"
@remove-ghosts="removeGhosts"
/> />
</div> </div>
</template> </template>
@ -52,6 +53,9 @@ export default defineComponent({
}, },
}, },
methods: { methods: {
removeGhosts() {
this.$emit("remove-ghosts");
},
updateChildItems(index, newItems) { updateChildItems(index, newItems) {
const updatedItems = [...this.items]; const updatedItems = [...this.items];
updatedItems[index] = { ...updatedItems[index], items: newItems }; updatedItems[index] = { ...updatedItems[index], items: newItems };

View File

@ -144,11 +144,13 @@
<div class="tab-content" style="height: 100%"> <div class="tab-content" style="height: 100%">
<div id="tab-tree" class="tab-pane" role="tabpanel"> <div id="tab-tree" class="tab-pane" role="tabpanel">
<FormDesignerTreeViewComponent <FormDesignerTreeViewComponent
:nodes="formJSON" :nodes="schema"
></FormDesignerTreeViewComponent> ></FormDesignerTreeViewComponent>
</div> </div>
<div id="tab-elements" class="tab-pane active" role="tabpanel"> <div id="tab-elements" class="tab-pane active" role="tabpanel">
<FormDesignerToolsComponent></FormDesignerToolsComponent> <FormDesignerToolsComponent
@remove-ghosts="removeGhosts"
></FormDesignerToolsComponent>
</div> </div>
</div> </div>
</div> </div>
@ -164,6 +166,7 @@
<FormRendererComponent <FormRendererComponent
:schema="schema" :schema="schema"
@update-schema="addElementToForm" @update-schema="addElementToForm"
@remove-ghosts="removeGhosts"
/> />
<slot name="middle"></slot> <slot name="middle"></slot>
</div> </div>
@ -245,6 +248,9 @@ export default {
window.removeEventListener("resize", this.updateSizes); window.removeEventListener("resize", this.updateSizes);
}, },
methods: { methods: {
removeGhosts() {
this.schema = this.schema.filter((item) => item.ghost !== true);
},
updateSizes() { updateSizes() {
this.middleWidth = window.innerWidth - this.leftWidth - this.rightWidth; this.middleWidth = window.innerWidth - this.leftWidth - this.rightWidth;
this.bottomHeight = window.innerHeight - this.topHeight; this.bottomHeight = window.innerHeight - this.topHeight;
@ -320,7 +326,7 @@ export default {
}, },
computed: { computed: {
jsonOutput() { jsonOutput() {
return JSON.stringify(this.formJSON, null, 2); // JSON sauber formatieren return JSON.stringify(this.schema, null, 2); // JSON sauber formatieren
}, },
}, },
}; };

View File

@ -1,7 +1,8 @@
export class FormBlock { export class FormBlock {
constructor(type, props = {}) { constructor(type, props = {}, ghost) {
this.type = type; this.type = type;
this.props = props; this.props = props;
this.ghost = ghost ?? false;
} }
toJSON() { toJSON() {

View File

@ -0,0 +1,15 @@
import { defineStore } from "pinia";
export const useDragStore = defineStore("drag", {
state: () => ({
currentDraggedType: null,
}),
actions: {
setDraggedType(type) {
this.currentDraggedType = type;
},
clearDraggedType() {
this.currentDraggedType = null;
},
},
});