<template>
    <ul :id="componentId" v-drag-stop-propagation>
        <li v-for="(item, index) in list" :key="item.id">
            <slot :row="item.item" :index="index"></slot>
        </li>
    </ul>
</template>

<script>
/*
 * @description 可拖拽列表
 * @url https://github.com/SortableJS/Sortable
 * https://www.itxst.com/sortablejs/neuinffi.html
 * @prop data {Array} 数据列
 * @prop option {Object} 配置信息，完整配置信息如下
 */
// }
import Sortable from 'sortablejs';
let nextId = 1;
export default {
    name: "sortList",
    directives: {
        "DragStopPropagation": {
            bind: function (el, binding, vnode) {
                el.ondrop = function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                }
            }
        }
    },
    data() {
        return {
            instance: null,
            componentId: '',
            list: []
        }
    },
    props: {
        data: {
            type: Array,
            default() {
                return [];
            }
        },
        options: {
            type: Object,
            default() {
                return {};
            }
        }
    },
    watch: {
        data: {
            immediate: true,
            handler(newV, oldV = []) {
                if (!newV) return;
                let list = [];
                this.data.forEach(function (item) {
                    list.push({
                        item: item,
                        id: nextId++
                    })
                })
                this.list = list;
            }
        },
    },
    beforeMount() {
        this.componentId = "sortList" + Math.random().toString().substr(-4, 4) + new Date().getTime().toString().substr(-4, 4) + Math.random().toString().substr(-4, 4);
    },
    mounted() {
        let _that = this;
        this.instance = new Sortable(document.querySelector(`#${this.componentId}`), {
            group: this.componentId,  // or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
            sort: true,  // sorting inside list
            animation: 200,  // ms, animation speed moving items when sorting, `0` — without animation
            ghostClass: "sortable-ghost",  // Class name for the drop placeholder
            chosenClass: "sortable-chosen",  // Class name for the chosen item
            dragClass: "sortable-drag",  // Class name for the dragging item
            ...this.options,
            setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
                dataTransfer.setData('Text', dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent
            },
            // Element is chosen
            onChoose: function (/**Event*/evt) {
                //evt.oldIndex;  // element index within parent
                _that.$emit('onChoose', evt);
            },
            // Element is unchosen
            onUnchoose: function (/**Event*/evt) {
                // same properties as onEnd
                _that.$emit('onUnchoose', evt);
            },
            // Element dragging started
            onStart: function (/**Event*/evt) {
                _that.$emit('onStart', evt);
                //evt.oldIndex;  // element index within parent
            },
            // Element dragging ended
            onEnd: function (/**Event*/evt) {
                // _that.data[evt.oldIndex] = _that.data.splice(evt.newIndex, 1,_that.data[evt.oldIndex])[0];
                _that.data.splice(evt.newIndex, 0, ..._that.data.splice(evt.oldIndex, 1))
                _that.$emit('onEnd', evt);
                // var itemEl = evt.item;  // dragged HTMLElement
                // evt.to;    // target list
                // evt.from;  // previous list
                // evt.oldIndex;  // element's old index within old parent
                // evt.newIndex;  // element's new index within new parent
                // evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
                // evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
                // evt.clone // the clone element
                // evt.pullMode;  // when item is in another sortable: `"clone"` if cloning, `true` if moving
            },
            // Element is dropped into the list from another list
            onAdd: function (/**Event*/evt) {
                _that.$emit('onAdd', evt);
                // same properties as onEnd
            },
            // Changed sorting within list
            onUpdate: function (/**Event*/evt) {
                _that.$emit('onUpdate', evt);
                // same properties as onEnd
            },
            // Called by any change to the list (add / update / remove)
            onSort: function (/**Event*/evt) {
                _that.$emit('onSort', evt);
                // same properties as onEnd
            },
            // Element is removed from the list into another list
            onRemove: function (/**Event*/evt) {
                _that.$emit('onRemove', evt);
                // same properties as onEnd
            },
            // Attempt to drag a filtered element
            onFilter: function (/**Event*/evt) {
                _that.$emit('onFilter', evt);
                // var itemEl = evt.item;  // HTMLElement receiving the `mousedown|tapstart` event.
            },
            // Event when you move an item in the list or between lists
            onMove: function (/**Event*/evt, /**Event*/originalEvent) {
                _that.$emit('onMove', evt, originalEvent);
                // Example: https://jsbin.com/nawahef/edit?js,output
                // evt.dragged; // dragged HTMLElement
                // evt.draggedRect; // DOMRect {left, top, right, bottom}
                // evt.related; // HTMLElement on which have guided
                // evt.relatedRect; // DOMRect
                // evt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by default
                // originalEvent.clientY; // mouse position
                // return false; — for cancel
                // return -1; — insert before target
                // return 1; — insert after target
            },
            // Called when creating a clone of element
            onClone: function (/**Event*/evt) {
                _that.$emit('onClone', evt);
                // var origEl = evt.item;
                // var cloneEl = evt.clone;
            },
            // Called when dragging element changes position
            onChange: function (/**Event*/evt) {
                _that.$emit('onChange', evt);
                // evt.newIndex // most likely why this event is used is to get the dragging element's current index
                // same properties as onEnd
            }
        });
    },
    methods: {}
}
</script>

<style lang="less" scoped>
.move {
    cursor: all-scroll;
}

</style>
