Skip to content

Instantly share code, notes, and snippets.

@pradeep1991singh
Last active September 3, 2020 02:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pradeep1991singh/61094a290befa181bba52519a28b61cc to your computer and use it in GitHub Desktop.
Save pradeep1991singh/61094a290befa181bba52519a28b61cc to your computer and use it in GitHub Desktop.
SortableList support drag-drop feature
<!DOCTYPE html>
<html>
<head>
<title>Sortable</title>
</head>
<body>
<div id="list"></div>
<script type="text/javascript">
/**
* SortableList library code here
*/
"use strict";
let SortableList = (function (document) {
// 1: list constructor
function CustomSortableList(parentElement, data) {
// Set selectedItem initial value to null
this.selectedItem = null;
// Item default styles
this.itemStyle = `font-family: sans-serif; height: 25px; /*padding: 1px 5px; margin: 5px*/; border: 1px solid transparent; /*background: #ccc*/; line-height: 25px; /*border-radius: 3px*/;`;
try {
// Build & render list
let parentHtml = parentElement.innerHTML;
data.forEach((item, index) => {
parentHtml += `<li class="item" draggable="true" data-order="${index}" style="${this.itemStyle}">${item}</li>`;
})
parentElement.innerHTML = `<ul>${parentHtml}</ul>`;
// add drag-drop event listeners
document.querySelectorAll(`#${parentElement.id} .item`).forEach(item => {
// This event is fired when the user starts dragging an element or text selection.
item.addEventListener('dragstart', this.dragStartHandler.bind(this));
// This event is fired continuously when an element or text selection is being dragged and the mouse pointer
// is over a valid drop target (every 50 ms WHEN mouse is not moving ELSE much faster between 5 ms
// (slow movement) and 1ms (fast movement) approximately. This firing pattern is different than mouseover ).
item.addEventListener('dragover', this.dragOverHandler.bind(this));
// This event is fired when a dragged element or text selection enters a valid drop target.
item.addEventListener('dragenter', this.dragEnterHandler.bind(this));
// This event is fired when a dragged element or text selection leaves a valid drop target.
item.addEventListener('dragleave', this.dragLeaveHandler.bind(this));
// This event is fired when an element or text selection is dropped on a valid drop target.
item.addEventListener('drop', this.dropHandler.bind(this));
// The dragend event is fired when a drag operation is being ended
// (by releasing a mouse button or hitting the escape key).
item.addEventListener('dragend', this.dragEndHandler.bind(this));
});
}
catch (e) {
throw new Error(e);
}
}
// 2: drag and drop apis
CustomSortableList.prototype = {
dragStartHandler: function (e) {
// Add drag tracking class
e.target.classList.add('drag-start');
// Handle styles
this.handleStyle(e.target)
// Move effect
e.dataTransfer.effectAllowed = 'move';
// Add the target node's innerHTML to the data transfer object
e.dataTransfer.setData('text/html', e.target.innerHTML);
this.selectedItem = e.target;
},
dragOverHandler: function (e) {
e.preventDefault();
// Set the dropEffect to move
e.dataTransfer.dropEffect = 'move';
if (this.selectedItem != e.target) {
// Sort items
this.getItemIndex(this.selectedItem) < this.getItemIndex(e.target)
? e.target.parentElement.insertBefore(this.selectedItem, e.target.nextSibling)
: e.target.parentElement.insertBefore(this.selectedItem, e.target);
}
},
dragEnterHandler: function (e) {
e.target.classList.add('drag-enter');
},
dragLeaveHandler: function (e) {
e.target.classList.remove('drag-enter');
},
dropHandler: function (e) {
e.stopPropagation();
// Handle drop here
},
dragEndHandler: function (e) {
// Clear element classes
e.target.classList.remove('drag-start', 'drag-enter');
// remove drag-start styles
this.handleStyle(e.target);
},
handleStyle: function (targetElement) {
// Add drag-start styles
targetElement.className.indexOf('drag-start') > -1
? targetElement.setAttribute('style', `${this.itemStyle}border:1px solid #000;`)
: targetElement.setAttribute('style', `${this.itemStyle}`);
},
getItemIndex: function (item) {
const children = item.parentNode.children;
let i = children.length - 1
for (; i >= 0; i--) {
if (item == children[i]) {
break;
}
}
return i;
}
}
return CustomSortableList;
})(document);
let data = [
'A List Item',
'Another List Item',
'Yet Another List Item'
];
let parentElement = document.getElementById('list');
let list = new SortableList(parentElement, data);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment