domDragDrop.mjs

import get from 'lodash-es/get.js'
import isestr from 'wsemi/src/isestr.mjs'
import iseobj from 'wsemi/src/iseobj.mjs'
import genID from 'wsemi/src/genID.mjs'
import domDrag from 'wsemi/src/domDrag.mjs'
import createVnodeEmitter from './createVnodeEmitter.mjs'


/**
 * 自訂指令v-domdragdrop, 同群組元素間拖放時觸發@domdragdrop
 *
 * 指令值: 非空物件為啟用, 須給group(群組鍵字串, 未給拋錯), 其餘鍵(attIdentify、attGroup、attIndex、previewOpacity、previewDisabledOpacity、previewBackground、previewBorderWidth、previewBorderColor、timeDragStartDelay)轉給wsemi domDrag; 其他值為停用
 * 宿主每次重繪皆解除後依最新指令值重建; 拖曳中重建者拖曳延續, 後續事件送達新實例(wsemi domDrag)
 *
 * 事件內容為物件, evName為'start'、'move'、'enter'、'leave'或'drop', 其餘為domDrag之事件內容
 * 處理函式經Vue之監聽器(invoker)呼叫: 多個處理函式依序執行, 同步錯誤與Promise拒絕交Vue之錯誤處理(自處理函式所屬元件之$parent起經errorCaptured, 再Vue.config.errorHandler), 與原生v-on相同
 * 元件標籤上同時有@domdragdrop與@domdragdrop.native時只呼叫前者, 無前者時呼叫後者; 停用或解除綁定後不再觸發
 * 不支援.once、.capture、.passive, 事件名須小寫(@domdragdrop), 元素上之.native無效, 以上於綁定時警告; .ctrl、.shift、.alt、.meta使處理函式不被呼叫, .stop、.prevent、.left、.right與按鍵修飾字使處理函式拋錯, 皆無法於執行期警告
 * 綁定時於元素設ev-dragdrop屬性, 解除時改為'null'
 *
 * @returns {Object} 回傳Vue 2自訂指令定義物件, 以Vue.directive('domdragdrop', domDragDrop())或元件directives註冊
 */
function domDragDrop() {
    let kbEv = {}

    function bind(el, binding, vnode) {
        // console.log('bind', 'el', el, 'binding', binding, 'vnode', vnode)

        //id
        let id = `r${genID()}`
        el.setAttribute('ev-dragdrop', id)

        //init
        init(el, binding, vnode, true)

    }

    function update(el, binding, vnode) {
        // console.log('update', 'el', el, 'binding', binding)

        //clear
        clear(el)

        //init
        init(el, binding, vnode, false)

    }

    function unbind(el) {
        // console.log('unbind', 'el', el)

        //clear
        clear(el)

        //remove attr
        el.setAttribute('ev-dragdrop', null)

    }

    function init(el, binding, vnode, isBind) {

        //id
        let id = el.getAttribute('ev-dragdrop')

        //eff
        let eff = get(binding, 'value')
        eff = iseobj(eff)

        //check
        if (!eff) {
            return
        }

        //group
        let group = get(binding, 'value.group')
        if (!isestr(group)) {
            throw new Error(`invalid group: v-domdragdrop="{group:'need to input key for group'}"`)
        }

        //params
        let attIdentify = get(binding, 'value.attIdentify')
        let attGroup = get(binding, 'value.attGroup')
        let attIndex = get(binding, 'value.attIndex')
        let previewOpacity = get(binding, 'value.previewOpacity')
        let previewDisabledOpacity = get(binding, 'value.previewDisabledOpacity')
        let previewBackground = get(binding, 'value.previewBackground')
        let previewBorderWidth = get(binding, 'value.previewBorderWidth')
        let previewBorderColor = get(binding, 'value.previewBorderColor')
        let timeDragStartDelay = get(binding, 'value.timeDragStartDelay')

        //em, clear時dispose, 解除或重建後舊實例之事件不再送到處理函式; 錯誤寫法之警告只於bind時發出
        let em = createVnodeEmitter(vnode, 'domdragdrop', 'domdragdrop', { warn: isBind })

        //domDrag
        let ev = domDrag(el, { group, attIdentify, attGroup, attIndex, previewOpacity, previewDisabledOpacity, previewBackground, previewBorderWidth, previewBorderColor, timeDragStartDelay })
        // ev.on('change', (msg) => {
        //     console.log('change', msg)
        // })
        ev.on('start', (msg) => {
            // console.log('start', msg)
            em.emit({
                evName: 'start',
                ...msg,
            })
        })
        ev.on('move', (msg) => {
            // console.log('move', msg)
            em.emit({
                evName: 'move',
                ...msg,
            })
        })
        ev.on('enter', (msg) => {
            // console.log('enter', msg)
            em.emit({
                evName: 'enter',
                ...msg,
            })
        })
        ev.on('leave', (msg) => {
            // console.log('leave', msg)
            em.emit({
                evName: 'leave',
                ...msg,
            })
        })
        ev.on('drop', (msg) => {
            // console.log('drop', msg)
            em.emit({
                evName: 'drop',
                ...msg,
            })
        })

        //save ev
        kbEv[id] = { ev, em }

    }

    function clear(el) {

        //id
        let id = el.getAttribute('ev-dragdrop')

        if (kbEv[id]) {

            //dispose
            kbEv[id].em.dispose()

            //unbind
            kbEv[id].ev.unbind()

            //set null
            kbEv[id] = null

            //delete
            delete kbEv[id]

        }

    }

    return {
        bind,
        update,
        unbind,
    }
}


export default domDragDrop