Simple Vanilla Javascript Drag n Drop Reordering List
by ppgab
HTML
<script src="//code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<script src="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="dragster" class="form-group p-5">
<label for="reportFields">Configure a ordem e visibilidade dos campos</label>
<div class="list-group">
<div class="list-group-item draggable" draggable="true" dragstate="sitting">
Drag Test 1
</div>
<div class="list-group-item draggable" draggable="true" dragstate="sitting">
Drag Test 2
</div>
<div class="list-group-item draggable" draggable="true" dragstate="sitting">
Drag Test 3
</div>
</div>
</div>
CSS
[dragstate="hovered-top"]{
border-top: 3px blue solid;
}
[dragstate="hovered-bottom"]{
border-bottom: 3px blue solid;
}
[dragstate="ghosted"]{
opacity: 0.5;
box-shadow: 2px 2px 10px rgba(0,0,0,.25) inset, -2px -2px 10px white inset;
}
JavaScript
class Orderable{
constructor(parentEle, eleSelector, containerSelector){
this.parentEle = parentEle;
this.eleSelector = eleSelector;
this.containerSelector = containerSelector;
this.beingDragged = false;
this.initEvents();
}
initEvents(){
this.parentEle.addEventListener('dragstart', evt => this.dragstart(evt));
this.parentEle.addEventListener('dragend', evt => this.dragend(evt));
this.parentEle.addEventListener('dragover', evt => this.dragover(evt));
this.parentEle.addEventListener('dragexit', evt => this.dragexit(evt));
this.parentEle.addEventListener('drop', evt => this.drop(evt));
}
dragstart(evt){
if(evt.target.matches(this.eleSelector)){
const ele = evt.target;
this.beingDragged = evt.target;
evt.dataTransfer.setData('text', 'dragging');
setTimeout(f => ele.setAttribute('dragstate','ghosted'),0);
}
}
dragend(evt){
evt.preventDefault();
this.beingDragged = false;
evt.target.setAttribute('dragstate', 'sitting');
}
dragover(evt){
evt.preventDefault();
if(evt.target.matches(this.containerSelector)){
const ele = evt.target;
if(! ele.isSameNode(this.beingDragged)){
if(this.evtIsAboveElement(evt,ele)){
if(! ele.isSameNode(this.beingDragged.nextElementSibling)){
ele.setAttribute('dragstate', 'hovered-top');
}
}else{
if(! ele.isSameNode(this.beingDragged.previousElementSibling)){
ele.setAttribute('dragstate', 'hovered-bottom');
}
}
}
}
}
drop(evt){
evt.preventDefault();
if(evt.target.matches(this.containerSelector)){
const ele = evt.target;
if(this.evtIsAboveElement(evt,ele)){
ele.insertAdjacentElement('beforebegin',this.beingDragged);
}else{
ele.insertAdjacentElement('afterend',this.beingDragged);
}
ele.setAttribute('dragstate', 'sitting');
}
}
dragexit(evt){
evt.preventDefault();
...