var DraggableList = (function () { 'use strict'; /* eslint-env browser */ const CLS_TRANSFORMED = 'draggable-list-transformed'; function posToIndex(rects, startIndex, y, bound) { if (y < rects[0].top && bound) return startIndex; for (let i = 0; i < startIndex; i++) { if (rects[i].bottom < y) continue; return i; } if (y > rects[rects.length - 1].bottom && bound) return startIndex; for (let i = rects.length - 1; i > startIndex; i--) { if (rects[i].top > y) continue; return i; } return startIndex; } function applyTransform(list, startIndex, oldIndex, newIndex, len) { if (newIndex > oldIndex) { transform(false, oldIndex, Math.min(startIndex - 1, newIndex - 1)); if (startIndex < list.length - 1) { transform(true, Math.max(oldIndex + 1, startIndex + 1), newIndex, "translateY(".concat(-len, "px)")); } } else { transform(false, Math.max(startIndex + 1, newIndex + 1), oldIndex); if (startIndex > 0) { transform(true, newIndex, Math.min(oldIndex - 1, startIndex - 1), "translateY(".concat(len, "px)")); } } function transform(state, p, q, style) { for (let i = p; i <= q; i++) { if (state && !list[i].classList.contains(CLS_TRANSFORMED)) { list[i].classList.add(CLS_TRANSFORMED); list[i].style.transform = style; } else if (!state && list[i].classList.contains(CLS_TRANSFORMED)) { list[i].classList.remove(CLS_TRANSFORMED); list[i].style = ''; } } } } function DraggableList(el, { bound, scrollContainer } = {}) { for (const c of el.children) { c.draggable = true; } new MutationObserver(records => { for (const r of records) { for (const n of r.addedNodes) { n.draggable = true; } } }).observe(el, { childList: true }); let startPos = null; let startIndex = 0; let dragOverIndex = 0; let dragOverPos = null; let rects = []; let dragTarget = null; let dropped = false; let itemSize = 0; el.addEventListener('dragstart', e => { if (e.target.parentNode !== el) return; dragTarget = e.target; dropped = false; const scrollLeft = scrollContainer ? scrollContainer.scrollLeft : 0; const scrollTop = scrollContainer ? scrollContainer.scrollTop : 0; startPos = { x: e.pageX + scrollLeft, y: e.pageY + scrollTop }; startIndex = [...el.children].indexOf(e.target); dragOverIndex = startIndex; dragOverPos = startPos; rects = [...el.children].map(el => { const r = el.getBoundingClientRect(); return { top: r.top + window.scrollY + scrollTop, bottom: r.bottom + window.scrollY + scrollTop }; }); itemSize = startIndex + 1 < rects.length ? rects[startIndex + 1].top - rects[startIndex].top : startIndex > 0 ? rects[startIndex].bottom - rects[startIndex - 1].bottom : 0; dragTarget.classList.add('draggable-list-target'); el.classList.add('draggable-list-dragging'); dispatch(e, 'd:dragstart'); }); el.addEventListener('dragenter', e => { if (dragTarget) { e.preventDefault(); dispatch(e, 'd:dragmove'); } }); el.addEventListener('dragover', e => { if (!dragTarget) return; e.preventDefault(); const scrollLeft = scrollContainer ? scrollContainer.scrollLeft : 0; const scrollTop = scrollContainer ? scrollContainer.scrollTop : 0; const newPos = { x: e.pageX + scrollLeft, y: e.pageY + scrollTop }; const newIndex = posToIndex(rects, startIndex, newPos.y, bound); applyTransform(el.children, startIndex, dragOverIndex, newIndex, itemSize); dragOverIndex = newIndex; dragOverPos = newPos; dispatch(e, 'd:dragmove'); }); document.addEventListener('dragend', e => { if (!dragTarget) return; for (const c of el.children) { c.classList.remove(CLS_TRANSFORMED); c.style = ''; } dragTarget.classList.remove('draggable-list-target'); el.classList.remove('draggable-list-dragging'); dispatch(e, 'd:dragend', { originalIndex: startIndex, spliceIndex: dragOverIndex, insertBefore: dragOverIndex < startIndex ? el.children[dragOverIndex] : el.children[dragOverIndex + 1], dropped }); dragTarget = null; }); el.addEventListener('drop', e => { if (dragTarget) { dropped = true; e.preventDefault(); } }); function dispatch(e, name, props) { const detail = { origin: e, startPos, currentPos: dragOverPos, dragTarget }; if (props) { Object.assign(detail, props); } el.dispatchEvent(new CustomEvent(name, { detail })); } } return DraggableList; })();