domIsVisible.mjs

import get from 'lodash-es/get.js'
import isfun from './isfun.mjs'
import isEle from './isEle.mjs'
import genPm from './genPm.mjs'
import evem from './evem.mjs'


function ckIOb() {
    try {
        return 'IntersectionObserver' in window
    }
    catch (err) {
        return false
    }
}


function ckIOE() {
    try {
        return 'IntersectionObserverEntry' in window
    }
    catch (err) {
        return false
    }
}


function ckIR() {

    function ckIRp() {
        try {
            return 'intersectionRatio' in window.IntersectionObserverEntry.prototype
        }
        catch (err) {
            return false
        }
    }

    function ckIRF() {
        //IE使用polyfill後IntersectionObserverEntry為函數, 檢核IntersectionObserverEntry.prototype會一樣過不了
        return isfun(window.IntersectionObserverEntry)
    }

    return ckIRp() || ckIRF()
}


function ckIO() {
    return !ckIOb() || !ckIOE() || !ckIR()
}


/**
 * 前端檢測DOM元素是否為顯示(使用者可見)狀態
 *
 * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/domIsVisible.test.mjs Github}
 * @memberOf wsemi
 * @param {Element} ele 輸入Element元素
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {String} [opt.mode='promise'] 輸入模式字串,可使用'promise'與'event',給予'promise'代表一次性偵測並回傳Promise,給予'event'代表持續性偵測並回傳EventEmitter,預設'promise'
 * @returns {Promise|Object} 回傳物件,給予'promise'時回傳Promise,resolve回傳顯示與否布林值,reject回傳錯誤訊息,給予'event'時回傳物件,可使用create、on、dispose函數,create代表開啟偵測並直至出現元素,on代表監聽'visible'事件可得元素顯隱變化,dispose代表中止偵測
 * @example
 * need test in browser
 *
 * let ele = document.querySelector('#id')
 *
 * domIsVisible(ele, { mode: 'promise' })
 *     .then(function(visible){
 *         console.log(visible)
 *         // => true or false
 *     })
 *     .catch(function(err){
 *         console.log(err)
 *     })
 *
 * let ev = domIsVisible(ele, { mode: 'event' })
 * ev.create()
 * ev.on('visible',(visible) => {
 *     console.log(visible)
 *     // => true or false
 * })
 * // ev.dispose()
 *
 */
function domIsVisible(ele, opt = {}) {

    //check ele
    if (!isEle(ele)) {
        return Promise.reject('invalid element')
    }

    //check IntersectionObserver
    if (ckIO()) {
        return Promise.reject('invalid IntersectionObserver')
    }

    //mode
    let mode = get(opt, 'mode', '')
    if (mode !== 'promise' && mode !== 'event') {
        mode = 'promise'
    }

    //corePm
    let corePm = () => {

        //pm
        let pm = genPm()

        try {

            //ob
            let ob = new IntersectionObserver((entries) => {

                //resolve
                pm.resolve(entries[0].isIntersecting)

                //disconnect
                ob.disconnect()

            })

            //observe
            ob.observe(ele)

        }
        catch (err) {
            pm.reject(err)
        }

        return pm
    }

    //coreEv
    let coreEv = () => {

        //ev
        let ev = evem()

        //watching
        let watching = false

        //ob
        let ob = new IntersectionObserver((entries) => {
            let b = entries[0].isIntersecting
            // console.log(ele, 'visible', b)
            ev.emit('visible', b)
        })

        //observe
        let observe = (ele) => {
            let b = false

            //check
            if (!isEle(ele)) {
                return b
            }

            //observe
            try {
                ob.observe(ele)
                b = true
            }
            catch (err) {
            // console.log('observe catch', err)
            }

            return b
        }

        //dispose
        let dispose = () => {
            let b = false
            try {
                ob.disconnect()
                b = true
            }
            catch (err) {
            // console.log('disconnect catch', err)
            }
            return b
        }

        //create
        let create = () => {
            let t = setInterval(() => {
                watching = observe(ele)
                if (watching) {
                    clearInterval(t)
                }
            }, 50)
        }

        //save
        ev.create = create
        ev.dispose = dispose

        return ev
    }

    //r
    let r = null
    if (mode === 'promise') {
        r = corePm()
    }
    else if (mode === 'event') {
        r = coreEv()
    }

    return r
}


export default domIsVisible