domShowImages.mjs

import get from 'lodash-es/get.js'
import merge from 'lodash-es/merge.js'
import cloneDeep from 'lodash-es/cloneDeep.js'
import size from 'lodash-es/size.js'
import isEle from './isEle.mjs'
import iseobj from './iseobj.mjs'
import isp0int from './isp0int.mjs'
import cint from './cint.mjs'
import genPm from './genPm.mjs'
import waitFun from './waitFun.mjs'
import getGlobal from './getGlobal.mjs'


function getViewer() {
    let g = getGlobal()
    let x = g.Viewer
    return x
}

//viewer.js工具指定值:
// 0: 隱藏
// 1: 永遠顯示
// 2: 螢幕寬度 ≥ 768px 才顯示
// 3: 螢幕寬度 ≥ 992px 才顯示
// 4: 螢幕寬度 ≥ 1200px 才顯示

function optOne() {
    return {
        button: false,
        navbar: false,
        title: false,
        toolbar: {
            zoomIn: 4,
            zoomOut: 4,
            oneToOne: 4,
            reset: 4,
            prev: 0, //關閉往前
            play: 0, //關閉播放
            next: 0, //關閉往後
            rotateLeft: 4,
            rotateRight: 4,
            flipHorizontal: 4,
            flipVertical: 4,
        },
        tooltip: false,
        movable: true,
        zoomable: true,
        rotatable: true,
        scalable: true,
        transition: true,
        fullscreen: false,
        keyboard: true,
        // url: 'src',
    }
}


function optMuti() {
    let r = optOne()
    r.navbar = true
    r.toolbar.prev = 4
    r.toolbar.next = 4
    return r
}


/**
 * 前端呼叫viewer.js顯示指定元素內圖片或圖片陣列
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/domShowImages.test.mjs Github}
 * @memberOf wsemi
 * @param {HTMLElement} eleImg 輸入圖片元素
 * @param {HTMLElement} [eleGroup=null] 輸入元素內含有多圖片元素,預設null
 * @param {Object} [opt={}] 輸入viewerjs設定物件,預設使用optOne或optMuti,若img僅一個則使用optOne,反之使用optMuti
 * @param {Integer} [opt.disTouchMoveToHide=4] 輸入手機touch觸發移動距離視為可隱藏整數,單位px,預設4
 * @returns {Promise} 回傳Promise,resolve回傳close訊息,reject回傳錯誤訊息
 * @example
 * need test in browser
 *
 * <img src="001.jpg" onclick="domShowImages(this)">
 * <img src="002.jpg" onclick="domShowImages(this,this.parentElement)">
 *
 */
async function domShowImages(eleImg, eleGroup = null, opt = {}) {
    let one = true
    let img = null

    //pm
    let pm = genPm()

    //check
    if (!iseobj(opt)) {
        opt = {}
    }

    //disTouchMoveToHide
    let disTouchMoveToHide = get(opt, 'disTouchMoveToHide', null)
    if (!isp0int(disTouchMoveToHide)) {
        disTouchMoveToHide = 4
    }
    disTouchMoveToHide = cint(disTouchMoveToHide)

    //img and check one
    if (!isEle(eleImg)) {
        pm.reject('eleImg is not a HTMLElement')
        return pm
    }
    else {
        img = eleImg //預設先使用自己
    }
    if (eleGroup !== null) {
        if (!isEle(eleGroup)) {
            pm.reject('eleGroup is not a HTMLElement')
            return pm
        }
        else {
            one = false
            img = eleGroup //若有群組(父層)元素則使用群組(父層)元素
        }
    }

    //check one
    if (!one) { //若有使用群組(父層)元素
        let imgs = eleGroup.querySelectorAll('img')
        let n = size(imgs)
        if (n === 0) {
            pm.reject('eleGroup does not contain any img')
            return pm
        }
        else if (n === 1) {
            one = true //eleGroup其內只有一張圖片
        }
    }

    //useOpt
    let useOpt = optOne()
    if (!one) {
        useOpt = optMuti()
    }
    useOpt = merge(useOpt, cloneDeep(opt))

    //shown
    useOpt.shown = function () {
        // console.log('shown')

        let core = async() => {

            //ele
            let ele = null

            //shown執行時未必有vw.viewer, 得須等待再掛載監聽
            await waitFun(() => {
                ele = vw.viewer
                let b = isEle(ele)
                return b
            })
            // console.log('ele', ele)

            // let img = ele.querySelector('img')
            // console.log('img', img)

            //isOnBackdrop
            let isOnBackdrop = (clientX, clientY) => {

                //eles
                let eles = document.elementsFromPoint(clientX, clientY)
                // console.log('eles', eles)

                //img
                let img = eles.find(el =>
                    el.tagName === 'IMG'
                )
                // console.log('img', img)

                //check
                if (!isEle(img)) {
                    return true
                }

                //b, 若img的class含有viewer-move, 代表點擊在viewer.js的img上
                let b = img?.classList?.contains('viewer-move')

                return !b
            }

            //偵測輕點
            let bTouch = false
            let x = 0
            let y = 0
            let dis = 0
            ele.addEventListener('touchstart', (ev) => {
                // console.log('touchstart', ev)

                //update
                let t = ev.touches[0]
                x = t.clientX
                y = t.clientY

                //check
                if (isOnBackdrop(x, y)) {
                    bTouch = true
                }

            }, { passive: false })
            ele.addEventListener('touchmove', (ev) => {
                // console.log('touchmove', ev)

                //check
                if (!bTouch) {
                    return
                }

                //dx, dy
                let t = ev.touches[0]
                let _x = t.clientX
                let _y = t.clientY
                let dx = _x - x
                let dy = _y - y

                //d
                let d = Math.sqrt(dx * dx + dy * dy)

                //累加移動距離
                dis += d
                // console.log('update dis', dx, dy, d, dis)

                //update
                x = t.clientX
                y = t.clientY

            }, { passive: false })
            ele.addEventListener('touchend', (ev) => {
                // console.log('touchend', ev)

                //check
                if (!bTouch) {
                    return
                }

                //check
                if (dis < disTouchMoveToHide) {
                    // console.log('vw.hide(from touch)')

                    //若點擊可顯示viewer.js圖片, 須阻止後續合成click觸發, 否則於手機會造成觸發WebKit的tap highlight, 使用者體驗不佳
                    ev.preventDefault()
                    ev.stopPropagation()

                    vw.hide(true) //立即關閉不用淡出動畫

                }
                else {
                    // console.log('drag')
                }

                //reset
                bTouch = false
                dis = 0

            }, { passive: false }) //必須使用passive=false否則無法cancel
            ele.addEventListener('touchcancel', (ev) => {
                // console.log('touchcancel', ev)

                //reset
                bTouch = false
                dis = 0

            })

        }
        core()
            .catch((err) => {
                console.log(err)
            })

    }

    //hide
    let bHide = false
    useOpt.hide = function () {
        // console.log('hide')

        //因hide事件會被hide繼續調用而產生無限迴圈, 故需通過bHide紀錄是否強制隱藏狀態來避免此問題
        //隱藏時因有transition會淡出, 但此時又點擊圖片要顯示時, 因會點到半透明背景而使點擊失效, 故通過強制vw.hide(true)使能馬上再次點擊顯示圖片
        if (!bHide) {
            bHide = true
            vw.hide(true) //立即關閉不用淡出動畫
        }

    }

    //destroy at hidden
    useOpt.hidden = function () {
        //console.log('hidden')

        //destroy
        vw.destroy()

        //resolve
        pm.resolve('close')

    }

    //UseViewer
    let UseViewer = getViewer()

    //vw
    let vw = new UseViewer(img, useOpt)

    //執行函數直接顯示
    vw.show()

    return pm
}


export default domShowImages