|
@@ -9,7 +9,8 @@ const props = defineProps({
|
|
|
attributes: { type: Object, default: () => ({}) },
|
|
|
options: { type: Object, default: () => ({}) },
|
|
|
tag: { type: String, default: "div" },
|
|
|
- class: { type: String, default: "" }
|
|
|
+ class: { type: String, default: "" },
|
|
|
+ disabled: { type: [Boolean, Function], default: false }
|
|
|
});
|
|
|
|
|
|
const mounted = ref(false);
|
|
@@ -22,7 +23,12 @@ const emit = defineEmits(["update:list", "start", "end", "update"]);
|
|
|
|
|
|
// When an element starts being dragged
|
|
|
const onDragStart = (itemIndex: number, event: DragEvent) => {
|
|
|
- // console.log(111, event);
|
|
|
+ const { draggable } = event.target;
|
|
|
+
|
|
|
+ if (props.disabled === true || !draggable) {
|
|
|
+ event.preventDefault();
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
// Set the effect of moving an element, which by default is clone. Not being used right now
|
|
|
event.dataTransfer.dropEffect = "move";
|
|
@@ -43,8 +49,16 @@ const onDragStart = (itemIndex: number, event: DragEvent) => {
|
|
|
};
|
|
|
|
|
|
// When a dragging element hovers over another draggable element, this gets triggered, usually many times in a second
|
|
|
-const onDragOver = (itemIndex: number) => {
|
|
|
- // console.log(321, itemIndex);
|
|
|
+const onDragOver = (itemIndex: number, event: DragEvent) => {
|
|
|
+ const getDraggableElement = element =>
|
|
|
+ element.classList.contains("draggable-item")
|
|
|
+ ? element
|
|
|
+ : getDraggableElement(element.parentElement);
|
|
|
+ const draggableElement = getDraggableElement(event.target);
|
|
|
+ const { draggable } = draggableElement;
|
|
|
+
|
|
|
+ if (props.disabled === true || !draggable) return;
|
|
|
+
|
|
|
// The index and list name of the item that is being dragged, stored in window since it can come from another list as well
|
|
|
const fromIndex = window.draggingItemIndex;
|
|
|
const fromList = window.draggingItemListName;
|
|
@@ -52,8 +66,6 @@ const onDragOver = (itemIndex: number) => {
|
|
|
const toIndex = itemIndex;
|
|
|
const toList = props.name;
|
|
|
|
|
|
- // console.log(3211, fromIndex, fromList, toIndex, toList);
|
|
|
-
|
|
|
// If the item hasn't changed position in the same list, don't continue
|
|
|
if (fromIndex === toIndex && fromList === toList) return;
|
|
|
|
|
@@ -107,26 +119,50 @@ const convertAttributes = item =>
|
|
|
typeof value === "function" ? value(item) : value
|
|
|
])
|
|
|
);
|
|
|
+
|
|
|
+function hasSlotContent(slot: Slot | undefined, slotProps = {}): boolean {
|
|
|
+ if (!slot) return false;
|
|
|
+
|
|
|
+ return slot(slotProps).some((vnode: VNode) => {
|
|
|
+ if (
|
|
|
+ vnode.type === Comment ||
|
|
|
+ vnode.type.toString() === "Symbol(Comment)"
|
|
|
+ )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (Array.isArray(vnode.children) && !vnode.children.length)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return (
|
|
|
+ vnode.type !== Text ||
|
|
|
+ vnode.type.toString() === "Symbol(Text)" ||
|
|
|
+ (typeof vnode.children === "string" && vnode.children.trim() !== "")
|
|
|
+ );
|
|
|
+ });
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <component
|
|
|
- :is="tag"
|
|
|
- v-for="(item, itemIndex) in list"
|
|
|
- :key="item[itemKey]"
|
|
|
- draggable="true"
|
|
|
- @dragstart="onDragStart(itemIndex, $event)"
|
|
|
- @dragenter.prevent
|
|
|
- @dragover.prevent="onDragOver(itemIndex)"
|
|
|
- @dragend="onDragEnd()"
|
|
|
- @drop.prevent="onDrop()"
|
|
|
- :data-index="itemIndex"
|
|
|
- :data-list="name"
|
|
|
- v-bind="convertAttributes(item)"
|
|
|
- class="draggable-item"
|
|
|
- >
|
|
|
- <slot name="item" :element="item"></slot>
|
|
|
- </component>
|
|
|
+ <template v-for="(item, itemIndex) in list" :key="item[itemKey]">
|
|
|
+ <component
|
|
|
+ v-if="hasSlotContent($slots.item, { element: item })"
|
|
|
+ :is="tag"
|
|
|
+ :draggable="
|
|
|
+ typeof disabled === 'function' ? !disabled(item) : !disabled
|
|
|
+ "
|
|
|
+ @dragstart="onDragStart(itemIndex, $event)"
|
|
|
+ @dragenter.prevent
|
|
|
+ @dragover.prevent="onDragOver(itemIndex, $event)"
|
|
|
+ @dragend="onDragEnd()"
|
|
|
+ @drop.prevent="onDrop()"
|
|
|
+ :data-index="itemIndex"
|
|
|
+ :data-list="name"
|
|
|
+ class="draggable-item"
|
|
|
+ v-bind="convertAttributes(item)"
|
|
|
+ >
|
|
|
+ <slot name="item" :element="item"></slot>
|
|
|
+ </component>
|
|
|
+ </template>
|
|
|
</template>
|
|
|
|
|
|
<style>
|