Draggable/Sortable List
by Konstantin Rouda
HTML
<section class="c-container">
<ul class="o-list o-list--sortable jsSortableList">
<li>1) Stewie Griffin</li>
<li>2) Lois Griffin</li>
<li>3) Peter Griffin</li>
<li>4) Meg Griffin</li>
<li>5) Chris Griffin</li>
<li>6) Brian Griffin</li>
<li>7) Glenn Quagmire</li>
<li>8) Joe Swanson</li>
</ul>
</section>
CSS
HTML {
font-size: 100%;
line-height: 1.5;
box-sizing: border-box;
}
BODY {
height: 100vh;
margin: 0;
}
*, *::before, *::after {
box-sizing: inherit;
color: inherit;
}
/*Actual Style*/
.c-container {
max-width: 350px;
margin: 5em auto 0;
}
.o-list {
position: relative;
list-style: none;
padding: 1px;
}
.o-list > LI {
padding: .5em 1em;
border: 1px solid;
/*cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;*/
margin-top: 1rem;
user-select: none;
}
.o-list--sortable > LI:hover {
cursor: move;
}
/*helpers*/
.o-drop-placeholder {
position: static !important;
display: list-item;
width: 100%;
//visibility: hidden;
opacity: .5;
border: 1px dashed !important;
}
.o-list__item--draggable {
position: absolute;
width: 100%;
//margin: 0 !important;
box-shadow: 3px 3px 6px rgba(0, 0, 0, .2);
z-index: 999;
background: rgb(202, 241, 255);
}
JavaScript
;(function() {
"use strict";
const list = document.querySelector(".jsSortableList");
const listItems = list.querySelectorAll("LI");
const DROP_PLACEHOLDER_ELEM_CLASS = "o-drop-placeholder";
const DROP_PLACEHOLDER_ELEM_ID = "drop-placeholder";
const DRAGGABLE_ITEM_STYLE_CLASS = "o-list__item--draggable";
const parentWidth = list.clientWidth,
parentHeight = list.clientHeight;
let listItemsDimensions = [];
/// calculates list items dimensions at the beginning
caculateListItemsDimensions();
let isMouseDown = false;
let mouseX, mouseY,
elemTop, elemLeft,
diffX, diffY;
let currentDraggable = null,
currentUpperBound,
currentBottomBound,
draggableHalfHeight,
currentDraggableMarginOffset = 0;
/*======================
Add EveneListeners
========================*/
list.addEventListener("mousedown", onMouseDown);
list.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
/*======================
Events
========================*/
function onMouseDown(e) {
/// prevents mouse down which fires outside the list
if(e.target === list || e.target.parentNode !== list) return;
currentDraggable = e.target;
isMouseDown = true;
mouseX = e.clientX;
mouseY = e.clientY;
draggableHalfHeight = (currentDraggable.offsetHeight / 2);
currentDraggableMarginOffset = parseInt(getComputedStyle(currentDraggable).marginTop);
/// creates element for placeholder
let dropPlaceholderElem = createDropPlaceHolder(DROP_PLACEHOLDER_ELEM_CLASS, currentDraggable);
let nextElem = currentDraggable.nextElementSibling;
if(nextElem) { /*puts placeholder before adjacent sibling (that is visually below the draggable element) element if it exists*/
nextElem.parentNode.insertBefore(dropPlaceholderElem, nextElem);
} else { /*append placeholder...