List dragging
by Kingdaro
HTML
<div class='list-items'></div>
CSS
/*
cosmetic information should be in the CSS styling
specifically, parts of the app that the script doesn't functionally rely on,
such as position:; and left/top:;
*/
body {
font: 16pt sans-serif;
padding: 50px;
}
.item {
cursor: pointer;
transition: 0.2s;
}
.item:hover {
color: gray;
}
JavaScript
(function() {
'use strict'
// it's much more straight-forward logic-wise to keep internal data of what we have,
// then editing the DOM based off of that
// as opposed to just using the actual DOM to keep our information.
// for example, adding a feature to the page to add new elements
// is as easy as adding to this array, then calling reorderItems() again.
let itemList = []
function killEvent(event) {
event.preventDefault()
event.stopPropagation()
}
function setItemTop(item, top) {
item.$element.style.top = (item.top = top) + 'px'
}
function correctItemElementPosition(item, index) {
setItemTop(item, index * 24)
}
function reorderItems(exception) {
// sort each item in the itemList array by the element's position
itemList.sort((a, b) => Math.sign(a.top - b.top))
// then reset each position of each item's element according to its index
// make sure to keep the position of the exception item (for dragging, mainly)
let top = exception.top
itemList.forEach(correctItemElementPosition)
setItemTop(exception, top)
}
function newItem(text) {
let $element = document.createElement('div')
// we *could* just parseInt() the element's style top whenever we needed it
// buuuuut it's better logic-wise to keep an internal position
let top = itemList.length * 24
// <3 es6
let item = { $element, top }
$element.className = 'item'
$element.innerText = text
$element.style.position = 'absolute'
$element.style.top = top + 'px'
let transition = $element.style.transition
function drag(event) {
$element.style.top = (item.top += event.movementY) + 'px'
reorderItems(item)
}
function startDrag(event) {
document.addEventListener('mousemove', drag)
// when the transition is enabled on a dragged element,
// it'll feel awkward and unresponsive because of how CSS transition:; works
...