Vue 2 – Dragover a child element pass the event to the parent depending of what we drag

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>