import filter from 'lodash-es/filter.js'
import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import evem from './evem.mjs'
import domCancelEvent from './domCancelEvent.mjs'
import pmSeries from './pmSeries.mjs'
import genPm from './genPm.mjs'
import isIE from './isIE.mjs'
async function readFilePromise(entry) {
let pm = genPm()
try {
entry.file(pm.resolve, pm.reject)
}
catch (err) {
pm.reject(err)
}
return pm
}
async function readEntriesPromise(directoryReader) {
let pm = genPm()
try {
directoryReader.readEntries(pm.resolve, pm.reject)
}
catch (err) {
pm.reject(err)
}
return pm
}
async function treeItem(item) {
let r = []
//pm
let pm = genPm()
async function tree(item) {
let file = null
if (item.isFile) {
file = await readFilePromise(item)
}
r.push({
type: item.isDirectory ? 'folder' : item.isFile ? 'file' : 'unknow',
path: item.fullPath,
name: item.name,
entry: item,
file,
})
if (item.isDirectory) {
let directoryReader = item.createReader()
let entries = await readEntriesPromise(directoryReader)
await pmSeries(entries, async (entry) => {
await tree(entry)
})
}
}
//tree
await tree(item)
//resolve
pm.resolve(r)
return pm
}
async function treeItems(items) {
let rs = []
await pmSeries(items, async (item) => {
let r = await treeItem(item)
each(r, (vv) => {
rs.push(vv)
})
})
return rs
}
async function treeEntries(items) {
//its
let its = []
for (let i = 0; i < items.length; i++) {
let item = items[i].webkitGetAsEntry()
if (item) {
its.push(item)
}
}
//treeItems
let r = await treeItems(its)
return r
}
async function treeFiles(files) {
let r = []
each(files, (v) => {
if (v.type) {
r.push({
type: 'file',
name: v.name,
file: v,
})
}
})
return r
}
async function treeDataTransfer(dataTransfer) {
let files = []
let entries = []
try {
//files, 全部瀏覽器
files = await treeFiles(get(dataTransfer, 'files', []))
//entries, 非IE11與Opera瀏覽器
if (!isIE()) {
entries = await treeEntries(get(dataTransfer, 'items', []))
}
}
catch (err) {
return Promise.reject(err)
}
return {
files,
entries,
}
}
/**
* 前端取得拖曳進指定元素的檔案陣列
*
* Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/domDropFiles.test.mjs Github}
* @memberOf wsemi
* @param {HTMLElement} ele 輸入dom元素
* @returns {Object} 回傳物件,包含emit與off事件,emit可監聽dropIn、dropOut、getFiles,通過監聽getFiles即可取得拖曳進指定元素的檔案陣列,並呼叫其內回調函數cb,方能繼續觸發dropOut事件
* @example
* need test in browser
*
* let ele = document.querySelector('#id')
* let ev = domDropFiles(ele)
* ev.on('getFiles', ({ files, filesTree, entries, cb }) => {
* console.log(files, filesTree, entries)
* cb()
* })
* ev.on('dropIn', () => {
* console.log('dropIn')
* })
* ev.on('dropOut', () => {
* console.log('dropOut')
* })
* ev.on('error', (err) => {
* console.log('error', err)
* })
*
*/
function domDropFiles(ele) {
let bMouseIn = false
let bMouseInTemp = false
//ev
let ev = evem()
//addEventListener
ele.addEventListener('dragenter', dgDragin, false)
ele.addEventListener('dragover', dgDragin, false)
ele.addEventListener('dragleave', dgDragout, false)
ele.addEventListener('drop', dgDrop, false)
function dgIn(e) {
domCancelEvent(e)
bMouseInTemp = true //所有滑鼠進入或移動都標記為滑鼠移入狀態
if (bMouseIn === false) {
bMouseIn = true
ev.emit('dropIn', { ev: e })
}
}
function dgOut(e) {
domCancelEvent(e)
bMouseInTemp = false //暫時視為滑鼠移出
setTimeout(function() {
if (!bMouseInTemp) { //若100ms後仍為滑鼠移出狀態才emit事件
bMouseIn = false
ev.emit('dropOut', { ev: e })
}
}, 100)
}
function dgDragin(e) {
dgIn(e)
}
function dgDragout(e) {
dgOut(e)
}
function dgDrop(e) {
//dgIn
dgIn(e)
//cb for dgOut
function cb() {
dgOut(e)
}
//treeDataTransfer
treeDataTransfer(e.dataTransfer)
.then((r) => {
//filesTree
let filesTree = filter(r.entries, { type: 'file' })
//emit
ev.emit('getFiles', {
ev: e,
files: r.files,
filesTree,
entries: r.entries,
cb
})
})
.catch((err) => {
ev.emit('error', err)
})
}
//off
function off() {
ele.removeEventListener('dragenter', dgDragin, false)
ele.removeEventListener('dragover', dgDragin, false)
ele.removeEventListener('dragleave', dgDragout, false)
ele.removeEventListener('drop', dgDrop, false)
}
ev.off = off
return ev
}
export default domDropFiles