Skip to content

Instantly share code, notes, and snippets.

@plugn
Forked from anonymous/index.html
Last active February 15, 2017 17:46
Show Gist options
  • Select an option

  • Save plugn/9c0beec3d3dd8d50e43560a36cdc7c7e to your computer and use it in GitHub Desktop.

Select an option

Save plugn/9c0beec3d3dd8d50e43560a36cdc7c7e to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style id="jsbin-css">
li {
box-sizing: border-box;
padding: 10px
}
#app [draggable=true] {
outline: 1px solid #eee;
margin: 5px 0;
}
</style>
</head>
<body onload="initDnD();">
<div id="app">
<ul>
<li>item01</li>
<li>item02</li>
<li>item03</li>
<li><span>groupA</span>
<ul>
<li>itemA1</li>
<li>itemA2</li>
<li>itemA3</li>
</ul>
</li>
<li>item04</li>
<li>item05</li>
<li><span>groupB</span>
<ul>
<li>itemB1</li>
<li>itemB2</li>
<li>itemB3</li>
</ul>
</li>
</ul>
</div>
<script id="jsbin-javascript">
function byId (id) { return document.getElementById(id); }
function byQS (qs) { return document.querySelectorAll(qs); }
function listFn (nodeList, fn, arg) {
return Array.prototype[fn].call(nodeList, arg)
}
function getOffset(e) {
var target = e.target || e.srcElement,
rect = target.getBoundingClientRect(),
offsetX = e.clientX - rect.left,
offsetY = e.clientY - rect.top;
return [offsetX, offsetY];
}
var dragged = null,
ghostEl = null,
counter = 0;
function initDnD() {
dragged = null;
ghostEl = null;
console.clear();
console.log('='.repeat(64));
listFn(byQS('#app li'), 'forEach', function(li){
li.draggable = true;
li.dataset.value = ''+(counter++)+'@'+li.innerText;
});
var rootEl = document.querySelector('#app > ul');
rootEl.addEventListener('dragstart', onDragStart, false)
rootEl.addEventListener('dragend', onDragEnd, false)
rootEl.addEventListener('dragover', onDragOver, false);
rootEl.addEventListener('drop', onDrop, false);
}
function onDragStart(e) {
ghostEl = null;
dragged = e.target;
console.log('dragstart', e.target.dataset.value);
}
// TODO: hide source draggable when dragging
function onDragOver(e) {
e.preventDefault();
if (e.target.draggable) {
var refNode = findRefNode(e);
e.target.parentNode.insertBefore(getGhost(), refNode);// e.target.parentNode.insertBefore(getGhost(), e.target);
}
}
function onDragEnd(e) {
if (ghostEl && ghostEl.parentNode) {
ghostEl.parentNode.removeChild(ghostEl);
}
ghostEl = null;
}
function onDrop(e) {
// TODO
// from: id, parentId
// to: [ parentId? ]id
console.log('drop. dragged:', dragged.dataset.value);
if (!e.target.dataset.value) {
var parentLi = e.target.closest('li'),
ul = parentLi && parentLi.querySelector('ul');
console.log('ul', ul);
if (ul) {
dragged.parentNode.removeChild( dragged );
ul.appendChild( dragged );
}
} else {
calcPos(e);
}
}
function findRefNode(e) {
if (dragged && e.target === dragged) { return; }
var ctxBox = e.target.getBoundingClientRect();
var offset = getOffset(e);
console.log('findRefNode', e.target.dataset.value, 'boxH', ctxBox.height, 'offsetY', offset);
return (offset[1] < ctxBox.height / 2) ? e.target : null;
}
// onDragEnter, onDragLeave
function getGhost() {
if (!dragged) { return; }
if (ghostEl) { return ghostEl; }
ghostEl = dragged.cloneNode(false);
ghostEl.style.opacity = '0.5';
return ghostEl;
}
function calcPos(e) {
var ghost = getGhost();
var targetIndex = ghost && getItemIndex(ghost);
console.log('calcPos() targetIndex', targetIndex, getList(e.target));
}
function getList(el) {
return listFn(el.parentNode.childNodes, 'filter', function(node){
return node.draggable;
});
}
function getItemIndex(el) {
// target node index inside it's parent
var targetList = getList(el);
return listFn(targetList, 'indexOf', el);
}
</script>
<script id="jsbin-source-css" type="text/css">li {
box-sizing: border-box;
padding: 10px
}
#app [draggable=true] {
outline: 1px solid #eee;
margin: 5px 0;
}
</script>
<script id="jsbin-source-javascript" type="text/javascript">
function byId (id) { return document.getElementById(id); }
function byQS (qs) { return document.querySelectorAll(qs); }
function listFn (nodeList, fn, arg) {
return Array.prototype[fn].call(nodeList, arg)
}
function getOffset(e) {
var target = e.target || e.srcElement,
rect = target.getBoundingClientRect(),
offsetX = e.clientX - rect.left,
offsetY = e.clientY - rect.top;
return [offsetX, offsetY];
}
var dragged = null,
ghostEl = null,
counter = 0;
function initDnD() {
dragged = null;
ghostEl = null;
console.clear();
console.log('='.repeat(64));
listFn(byQS('#app li'), 'forEach', function(li){
li.draggable = true;
li.dataset.value = ''+(counter++)+'@'+li.innerText;
});
var rootEl = document.querySelector('#app > ul');
rootEl.addEventListener('dragstart', onDragStart, false)
rootEl.addEventListener('dragend', onDragEnd, false)
rootEl.addEventListener('dragover', onDragOver, false);
rootEl.addEventListener('drop', onDrop, false);
}
function onDragStart(e) {
ghostEl = null;
dragged = e.target;
console.log('dragstart', e.target.dataset.value);
}
// TODO: hide source draggable when dragging
function onDragOver(e) {
e.preventDefault();
if (e.target.draggable) {
var refNode = findRefNode(e);
e.target.parentNode.insertBefore(getGhost(), refNode);// e.target.parentNode.insertBefore(getGhost(), e.target);
}
}
function onDragEnd(e) {
if (ghostEl && ghostEl.parentNode) {
ghostEl.parentNode.removeChild(ghostEl);
}
ghostEl = null;
}
function onDrop(e) {
// TODO
// from: id, parentId
// to: [ parentId? ]id
console.log('drop. dragged:', dragged.dataset.value);
if (!e.target.dataset.value) {
var parentLi = e.target.closest('li'),
ul = parentLi && parentLi.querySelector('ul');
console.log('ul', ul);
if (ul) {
dragged.parentNode.removeChild( dragged );
ul.appendChild( dragged );
}
} else {
calcPos(e);
}
}
function findRefNode(e) {
if (dragged && e.target === dragged) { return; }
var ctxBox = e.target.getBoundingClientRect();
var offset = getOffset(e);
console.log('findRefNode', e.target.dataset.value, 'boxH', ctxBox.height, 'offsetY', offset);
return (offset[1] < ctxBox.height / 2) ? e.target : null;
}
// onDragEnter, onDragLeave
function getGhost() {
if (!dragged) { return; }
if (ghostEl) { return ghostEl; }
ghostEl = dragged.cloneNode(false);
ghostEl.style.opacity = '0.5';
return ghostEl;
}
function calcPos(e) {
var ghost = getGhost();
var targetIndex = ghost && getItemIndex(ghost);
console.log('calcPos() targetIndex', targetIndex, getList(e.target));
}
function getList(el) {
return listFn(el.parentNode.childNodes, 'filter', function(node){
return node.draggable;
});
}
function getItemIndex(el) {
// target node index inside it's parent
var targetList = getList(el);
return listFn(targetList, 'indexOf', el);
}
</script></body>
</html>
li {
box-sizing: border-box;
padding: 10px
}
#app [draggable=true] {
outline: 1px solid #eee;
margin: 5px 0;
}
function byId (id) { return document.getElementById(id); }
function byQS (qs) { return document.querySelectorAll(qs); }
function listFn (nodeList, fn, arg) {
return Array.prototype[fn].call(nodeList, arg)
}
function getOffset(e) {
var target = e.target || e.srcElement,
rect = target.getBoundingClientRect(),
offsetX = e.clientX - rect.left,
offsetY = e.clientY - rect.top;
return [offsetX, offsetY];
}
var dragged = null,
ghostEl = null,
counter = 0;
function initDnD() {
dragged = null;
ghostEl = null;
console.clear();
console.log('='.repeat(64));
listFn(byQS('#app li'), 'forEach', function(li){
li.draggable = true;
li.dataset.value = ''+(counter++)+'@'+li.innerText;
});
var rootEl = document.querySelector('#app > ul');
rootEl.addEventListener('dragstart', onDragStart, false)
rootEl.addEventListener('dragend', onDragEnd, false)
rootEl.addEventListener('dragover', onDragOver, false);
rootEl.addEventListener('drop', onDrop, false);
}
function onDragStart(e) {
ghostEl = null;
dragged = e.target;
console.log('dragstart', e.target.dataset.value);
}
// TODO: hide source draggable when dragging
function onDragOver(e) {
e.preventDefault();
if (e.target.draggable) {
var refNode = findRefNode(e);
e.target.parentNode.insertBefore(getGhost(), refNode);// e.target.parentNode.insertBefore(getGhost(), e.target);
}
}
function onDragEnd(e) {
if (ghostEl && ghostEl.parentNode) {
ghostEl.parentNode.removeChild(ghostEl);
}
ghostEl = null;
}
function onDrop(e) {
// TODO
// from: id, parentId
// to: [ parentId? ]id
console.log('drop. dragged:', dragged.dataset.value);
if (!e.target.dataset.value) {
var parentLi = e.target.closest('li'),
ul = parentLi && parentLi.querySelector('ul');
console.log('ul', ul);
if (ul) {
dragged.parentNode.removeChild( dragged );
ul.appendChild( dragged );
}
} else {
calcPos(e);
}
}
function findRefNode(e) {
if (dragged && e.target === dragged) { return; }
var ctxBox = e.target.getBoundingClientRect();
var offset = getOffset(e);
console.log('findRefNode', e.target.dataset.value, 'boxH', ctxBox.height, 'offsetY', offset);
return (offset[1] < ctxBox.height / 2) ? e.target : null;
}
// onDragEnter, onDragLeave
function getGhost() {
if (!dragged) { return; }
if (ghostEl) { return ghostEl; }
ghostEl = dragged.cloneNode(false);
ghostEl.style.opacity = '0.5';
return ghostEl;
}
function calcPos(e) {
var ghost = getGhost();
var targetIndex = ghost && getItemIndex(ghost);
console.log('calcPos() targetIndex', targetIndex, getList(e.target));
}
function getList(el) {
return listFn(el.parentNode.childNodes, 'filter', function(node){
return node.draggable;
});
}
function getItemIndex(el) {
// target node index inside it's parent
var targetList = getList(el);
return listFn(targetList, 'indexOf', el);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment