ivue-material-plus
Version:
A high quality UI components Library with Vue.js
198 lines (195 loc) • 6.24 kB
JavaScript
import { reactive, provide } from 'vue';
import { removeClass, addClass } from '../../../utils/assist.mjs';
import { NODE_KEY } from '../utils.mjs';
const dragEventsKey = Symbol("IvueTreeDragEvents");
function useDragNodeHandler({
props,
ctx,
treeRef,
dropIndicator,
store
}) {
const dragState = reactive({
showDropIndicator: false,
draggingStartNode: null,
dropNode: null,
allowDrop: true,
dropType: null
});
const treeNodeDragStart = ({ event, treeNode }) => {
if (typeof props.allowDrag === "function" && !props.allowDrag(treeNode.node)) {
event.preventDefault();
return false;
}
event.dataTransfer.effectAllowed = "move";
try {
event.dataTransfer.setData("text/plain", "");
} catch (e) {
}
dragState.draggingStartNode = treeNode;
ctx.emit(
"on-node-drag-start",
treeNode.node,
event
);
};
const treeNodeDragOver = ({ event, treeNode }) => {
const dropNode = treeNode;
const oldDropNode = dragState.dropNode;
if (oldDropNode && oldDropNode !== dropNode) {
removeClass(oldDropNode.$el, "ivue-tree-drop-indicator");
}
const draggingStartNode = dragState.draggingStartNode;
if (!draggingStartNode || !dropNode) {
return;
}
let dropPrev = true;
let dropInner = true;
let dropNext = true;
let userAllowDropInner = true;
if (typeof props.allowDrop === "function") {
dropPrev = props.allowDrop(draggingStartNode.node, dropNode.node, "prev");
dropInner = props.allowDrop(
draggingStartNode.node,
dropNode.node,
"inner"
);
userAllowDropInner = dropInner;
dropNext = props.allowDrop(draggingStartNode.node, dropNode.node, "next");
}
event.dataTransfer.dropEffect = dropInner || dropPrev || dropNext ? "move" : "none";
if ((dropInner || dropPrev || dropNext) && oldDropNode !== dropNode) {
if (oldDropNode && oldDropNode.node.data[NODE_KEY] !== dropNode.node.data[NODE_KEY]) {
ctx.emit(
"on-node-drag-leave",
draggingStartNode.node,
oldDropNode.node,
event
);
}
ctx.emit(
"on-node-drag-enter",
draggingStartNode.node,
dropNode.node,
event
);
}
if (dropPrev || dropInner || dropNext) {
dragState.dropNode = dropNode;
}
if (dropNode.node.nextSibling === draggingStartNode.node) {
dropNext = false;
}
if (dropNode.node.prevSibling === draggingStartNode.node) {
dropPrev = false;
}
if (dropNode.node.contains(draggingStartNode.node, false)) {
dropInner = false;
}
if (draggingStartNode.node === dropNode.node || draggingStartNode.node.contains(dropNode.node)) {
dropPrev = false;
dropInner = false;
dropNext = false;
}
const targetPosition = dropNode.$el.getBoundingClientRect();
const treePosition = treeRef.value.getBoundingClientRect();
let dropType;
const prevPercent = dropPrev ? dropInner ? 0.25 : dropNext ? 0.45 : 1 : -1;
const nextPercent = dropNext ? dropInner ? 0.75 : dropPrev ? 0.55 : 0 : 1;
let indicatorTop = -9999;
const distance = event.clientY - targetPosition.top;
if (distance < targetPosition.height * prevPercent) {
dropType = "before";
} else if (distance > targetPosition.height * nextPercent) {
dropType = "after";
} else if (dropInner) {
dropType = "inner";
} else {
dropType = "none";
}
const iconPosition = dropNode.$el.querySelector(".ivue-tree-node--expand-icon").getBoundingClientRect();
const _dropIndicator = dropIndicator.value;
if (dropType === "before") {
indicatorTop = iconPosition.top - treePosition.top;
} else if (dropType === "after") {
indicatorTop = iconPosition.bottom - treePosition.top;
}
_dropIndicator.style.top = `${indicatorTop}px`;
_dropIndicator.style.left = `${iconPosition.right - treePosition.left}px`;
if (dropType === "inner") {
addClass(dropNode.$el, "is-drop-inner");
} else {
removeClass(dropNode.$el, "is-drop-inner");
oldDropNode && removeClass(oldDropNode.$el, "is-drop-inner");
}
dragState.showDropIndicator = dropType === "before" || dropType === "after";
dragState.allowDrop = dragState.showDropIndicator || userAllowDropInner;
dragState.dropType = dropType;
ctx.emit(
"on-node-drag-over",
draggingStartNode.node,
dropNode.node,
event
);
};
const treeNodeDragEnd = (event) => {
const { draggingStartNode, dropNode, dropType } = dragState;
event.dataTransfer.dropEffect = "move";
if (draggingStartNode && dropNode) {
const draggingStartNodeCopy = { data: draggingStartNode.node.data };
if (dropType !== "none") {
draggingStartNode.node.remove();
}
if (dropType === "before") {
dropNode.node.parent.insertBefore(draggingStartNodeCopy, dropNode.node);
} else if (dropType === "after") {
dropNode.node.parent.insertAfter(draggingStartNodeCopy, dropNode.node);
} else if (dropType === "inner") {
dropNode.node.insertChild(draggingStartNodeCopy);
}
if (dropType !== "none") {
store.value.registerNode(draggingStartNodeCopy);
}
removeClass(dropNode.$el, "is-drop-inner");
ctx.emit(
"on-node-drag-end",
draggingStartNode.node,
dropNode.node,
dropType,
event
);
if (dropType !== "none") {
ctx.emit(
"on-node-drop",
draggingStartNode.node,
dropNode.node,
dropType,
event
);
}
}
if (draggingStartNode && !dropNode) {
ctx.emit(
"on-node-drag-end",
draggingStartNode.node,
null,
dropType,
event
);
}
dragState.showDropIndicator = false;
dragState.draggingStartNode = null;
dragState.dropNode = null;
dragState.allowDrop = true;
};
provide(dragEventsKey, {
treeNodeDragStart,
treeNodeDragOver,
treeNodeDragEnd
});
return {
dragState
};
}
export { dragEventsKey, useDragNodeHandler };
//# sourceMappingURL=useDragNode.mjs.map