UNPKG

vue3-dragula

Version:
293 lines 10.1 kB
//--------------------------------------------------// // vue3-dragula // // Created by basicx-StrgV // // https://github.com/basicx-StrgV/ // //--------------------------------------------------// // Based on 'vue-dragula' by Astray-git // // https://github.com/Astray-git // //--------------------------------------------------// import dragula from 'dragula'; import mitt from 'mitt'; import { nextTick } from 'vue'; if (!dragula) { throw new Error('[vue3-dragula] Cannot locate package: dragula'); } if (!mitt) { throw new Error('[vue3-dragula] Cannot locate package: mitt'); } export const VueDragula = { install(app, options) { vueDragula(app); } }; export class Bag { constructor(name, drake) { this.drakeRegistert = false; this.initEvents = false; this.models = []; this.name = name; this.drake = drake; } destroy() { this.drakeRegistert = false; this.initEvents = false; this.models.splice(0, this.models.length); if (this.drake != null) { this.drake.destroy(); } this.drake = null; } } export class VueDragulaGlobal { } function vueDragula(vueApp) { const service = new DragulaService(); VueDragulaGlobal.eventBus = service.eventBus; VueDragulaGlobal.find = service.find.bind(service); VueDragulaGlobal.options = service.setOptions.bind(service); VueDragulaGlobal.injectOptions = service.injectOptions.bind(service); vueApp.directive('dragula', { beforeMount(container, binding, vnode) { let name = 'globalBag'; let drake; const bagName = vnode.props ? vnode.props['bag'] : null; if (bagName != null && bagName.trim().length !== 0) { name = bagName; } let bag = service.find(name); if (bag != null) { drake = bag.drake; if (drake == null) { return; } drake.containers.push(container); updateModelBinding(container, binding, vnode); return; } drake = dragula({ containers: [container] }); bag = service.add(name, drake); updateModelBinding(container, binding, vnode); service.handleModels(name, bag); }, updated(container, binding, vnode, oldVnode) { updateModelBinding(container, binding, vnode); }, unmounted(container, binding, vnode) { let unbindBagName = 'globalBag'; const bagName = vnode.props ? vnode.props['bag'] : null; if (bagName != null && bagName.trim().length !== 0) { unbindBagName = bagName; } let bag = service.find(unbindBagName); if (bag == null || bag.drake == null) { return; } let containerIndex = bag.drake.containers.indexOf(container); if (containerIndex > -1) { bag.drake.containers.splice(containerIndex, 1); } if (bag.drake.containers.length === 0) { service.destroy(unbindBagName); } } }); function updateModelBinding(container, binding, vnode) { let name = 'globalBag'; const newValue = vnode ? binding.value : null; if (newValue == null) { return; } const bagName = vnode.props ? vnode.props['bag'] : null; if (bagName != null && bagName.trim().length !== 0) { name = bagName; } const bag = service.find(name); if (bag == null) { return; } let modelContainer = service.findModelContainerByContainer(container, bag); if (modelContainer) { modelContainer.model = newValue; } else { bag.models.push({ model: newValue, container: container }); } } } class DragulaService { constructor() { this.bags = []; this.eventBus = mitt(); this.events = [ 'cancel', 'cloned', 'drag', 'dragend', 'drop', 'out', 'over', 'remove', 'shadow', 'dropModel', 'removeModel' ]; } add(name, drake) { let bag = this.find(name); if (bag != null) { throw new Error('[vue3-dragula] Bag named: "' + name + '" already exists.'); } bag = new Bag(name, drake); this.bags.push(bag); this.handleModels(name, bag); if (!bag.initEvents) { this.setupEvents(bag); } return bag; } find(name) { let bags = this.bags; for (const bag of bags) { if (bag.name === name) { return bag; } } return null; } handleModels(name, bag) { // Cancel if drake object does not exist or if it is already registert if (bag.drake == null || bag.drakeRegistert) { return; } let dragElm; let dragIndex; let isManualCancel = false; // On Remove event handler bag.drake.on('remove', (el, container, source) => { if (bag.drake == null) { return; } let sourceModel = this.findModelForContainer(source, bag); sourceModel.splice(dragIndex, 1); isManualCancel = true; bag.drake.cancel(true); // Emit removeModel event this.eventBus.emit('removeModel', [name, el, source, dragIndex]); }); // On Drag event handler bag.drake.on('drag', (el, source) => { dragElm = el; dragIndex = this.domIndexOf(el, source); }); // On Drop event handler bag.drake.on('drop', (dropElm, target, source) => { if (bag.drake == null || target == null) { return; } let dropIndex = this.domIndexOf(dropElm, target); let sourceModel = this.findModelForContainer(source, bag); let dropElmModel = null; if (target === source) { nextTick(() => { sourceModel.splice(dropIndex, 0, sourceModel.splice(dragIndex, 1)[0]); }); dropElmModel = sourceModel[dropIndex]; } else { let notCopy = dragElm === dropElm; let targetModel = this.findModelForContainer(target, bag); dropElmModel = notCopy ? sourceModel[dragIndex] : this.cloneObject(sourceModel[dragIndex]); if (notCopy) { nextTick(() => { sourceModel.splice(dragIndex, 1); }); } nextTick(() => { targetModel.splice(dropIndex, 0, dropElmModel); }); } isManualCancel = true; bag.drake.cancel(true); // Emit dropModel event this.eventBus.emit('dropModel', [name, dropElm, dropElmModel, target, source, dropIndex]); }); // On Cancel event handler bag.drake.on('cancel', (dropElm, container, source) => { // Only handle the cancel if it was triggerd by dragula and not from this library if (bag.drake == null || isManualCancel) { isManualCancel = false; return; } let sourceModel = this.findModelForContainer(source, bag); let dropElmModel = sourceModel[dragIndex]; // Emit cancelModel event this.eventBus.emit('cancelModel', [name, dropElm, dropElmModel, source]); }); // Set registration flag bag.drakeRegistert = true; } destroy(name) { let bag = this.find(name); if (bag == null) { return; } let bagIndex = this.bags.indexOf(bag); this.bags.splice(bagIndex, 1); bag.destroy(); } setOptions(name, options) { let bag = this.add(name, dragula(options)); if (bag.drake != null) { this.handleModels(name, bag); } } injectOptions(name, options) { let bag = this.find(name); if (bag == null) { throw new Error('[vue3-dragula] Bag named: "' + name + '" does not exists.'); } let currentContainers = []; if (bag.drake != null) { currentContainers = bag.drake.containers; bag.drake.destroy(); bag.drake = null; bag.drakeRegistert = false; bag.initEvents = false; } options.containers = currentContainers; bag.drake = dragula(options); this.handleModels(name, bag); this.setupEvents(bag); } setupEvents(bag) { bag.initEvents = true; let _this = this; let emitter = (type) => { function replicate() { let args = Array.prototype.slice.call(arguments); _this.eventBus.emit(type, [bag.name].concat(args)); } if (bag.drake != null) { bag.drake.on(type, replicate); } }; this.events.forEach(emitter); } domIndexOf(child, parent) { return Array.prototype.indexOf.call(parent.children, child); } findModelForContainer(container, bag) { var _a; return (_a = this.findModelContainerByContainer(container, bag)) === null || _a === void 0 ? void 0 : _a.model; } findModelContainerByContainer(container, bag) { return bag.models.find((model) => model.container === container); } cloneObject(object) { return JSON.parse(JSON.stringify(object)); } } //# sourceMappingURL=vue3-dragula.js.map