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();
   ...