I’m making a template editor with Vuejs and I don’t know how to make this:
I got one parent component that is a rowComponent and inside it got one child that is a container and inside that one, I got 2 text components.
rowComponent
________________container
_________________________textComponent
rowComponent and textComponent will both have a @mouseover and @drop.
rowComponent is listening mouseover because we can drop other rows on it and thats working great.
I need to put too a @mouseover and @drop on the child component (text) because I want to drop some other elements (like others texts) BUT I DON’T want to dragover and drop rows on it.
So when I’m overing childs (text) with a row block element, I want to propage the event to the parent so if I drop in the child a ROW block, it’s the @dragover (and drop) of the parent that is triggered. But I don’t know who to do that.
Of course, if I take a TEXT block, the child will accept the dragover and drop on himself
dragStart element :
<v-list-item v-for="item in rowContainers" :key="item.title">
<v-list-item-content
draggable
@dragstart="dragStart($event, item)"
:id="item.id"
class="d-flex justify-center mb-2"
style="border: 1px solid black"
>
{{ item.name }}
</v-list-item-content>
</v-list-item>
dragStart(event, item) {
console.log('dragging : ')
console.log(item)
event.dataTransfer.setData('item', item)
},
Row Component (parent):
<template>
<div
@dragover="dragOver"
@dragleave="dragleave"
@drop="handleDropRow"
@mouseover="isHovering = true"
@mouseout="isHovering = false"
@click.stop="selectRow"
class="blueprint-row"
:class="{
'blueprint-row-hovering': isHovering,
'blueprint-row-selected': isSelected,
'blueprint-row-drag-row-hover-top': dragHoverRowOnTop,
'blueprint-row-drag-row-hover-bot': dragHoverRowOnBot,
}"
>
<!-- Container block -->
<component
:is="block.component"
:block="block"
:blockId="block.id"
:rowIndex="index"
></component>
</div>
</template>
<script>
import SingleContainer from "./containers/SingleContainer.vue";
import { mapGetters, mapActions } from "vuex";
export default {
props: ["rowId", "block", "index"],
components: {
SingleContainer,
},
data() {
return {
isHovering: false,
dragHoverRowOnTop: false,
dragHoverRowOnBot: false,
};
},
mounted() {
console.log("mounted");
},
computed: {
...mapGetters("templateEditor", ["blockSelected"]),
isSelected() {
return this.blockSelected.id === this.block.id;
},
},
methods: {
...mapActions("templateEditor", ["setSelectedBlock"]),
selectRow() {
console.log("click on row " + this.block.id);
this.setSelectedBlock({ type: "row", id: this.block.id });
},
dragOver(e) {
e.preventDefault()
console.log(e.target)
const offset = this.getOffsetPosition(e);
console.log(offset)
// const target_index = this.getDataIndexById(e.target.id);
if (offset < 0) {
this.dragHoverRowOnTop = true
this.dragHoverRowOnBot = false
} else {
this.dragHoverRowOnBot = true
this.dragHoverRowOnTop = false
}
},
dragleave() {
this.dragHoverRowOnTop = false
this.dragHoverRowOnBot = false
},
handleDropRow(e) {
console.log("drop");
console.log(e);
},
getOffsetPosition(e) {
const box = e.target.getBoundingClientRect();
const offset = e.clientY - box.top - box.height / 2;
return offset;
},
},
};
</script>
container :
<template>
<div :style="computeRowStyle" >
<!-- has no children -->
<div
v-if="!block.children.length"
:class="{ 'dragcontent-hovering': dragContentOvering }"
>
<div
class="d-flex justify-center align-center items-center empty-content"
>
Pas de contenu ici. Glissez un nouvel élément depuis "contenu".
{{ blockId }}
</div>
</div>
<!-- has children -->
<div v-else style="width: 900px;" class="d-flex flex-column">
<div
v-for="(child, index) in block.children"
:key="index"
>
<TextTitle v-if="child.type === 'text-title'" :data="child" :rowIndex="rowIndex" :index="index" />
</div>
</div>
</div>
</template>
child (text):
<template>
<div
style="width: 100%"
:style="computeRowStyle"
:class="{ 'content-hovering': isHovering, 'content-selected': isSelected }"
@mouseover.stop="isHovering = true"
@mouseout="isHovering = false"
@dragover="dragOver"
@dragleave="dragleave"
@click.stop="selectContent"
>
<span contenteditable @input="update">{{ data.content }}</span>
</div>
</template>
<script>
import { mapGetters, mapActions } from "vuex";
export default {
props: ["data", "rowIndex", "index"],
data() {
return {
isHovering: false,
};
},
computed: {
...mapGetters("templateEditor", ["blockSelected"]),
isSelected() {
return this.blockSelected.id === this.data.id;
},
computeRowStyle() {
const rowStyle = {
textAlign: this.data.elementStyle.textAlign,
};
return rowStyle;
},
},
methods: {
...mapActions("templateEditor", ["setSelectedBlock", "updateTextValue"]),
selectContent() {
console.log("click on content " + this.data.id);
this.setSelectedBlock({ type: "text-title", id: this.data.id });
},
update(e) {
console.log(e.target.textContent);
// this.data.content = e.target.textContent
this.updateTextValue({
index: this.index,
rowIndex: this.rowIndex,
value: e.target.textContent,
});
},
dragOver(e) {
e.preventDefault()
console.log(e.dataTransfer)
// e.preventDefault();
// const offset = this.getOffsetPosition(e);
// console.log(offset);
// const target_index = this.getDataIndexById(e.target.id);
// if (offset < 0) {
// this.dragHoverRowOnTop = true;
// this.dragHoverRowOnBot = false;
// } else {
// this.dragHoverRowOnBot = true;
// this.dragHoverRowOnTop = false;
// }
},
getOffsetPosition(e) {
const box = e.target.getBoundingClientRect();
const offset = e.clientY - box.top - box.height / 2;
return offset;
},
},
};
</script>