toolshed-8.x-1.x-dev/assets/DragDrop.es6.js
assets/DragDrop.es6.js
(({ Toolshed }) => {
/**
* Object wrapping a DOM element to implement a droppable container for
* accepting draggable instances.
*/
class Droppable {
/**
* Create a new instance of a droppable for containing draggables.
*
* @param {Element} el
* DOM element to treat as the droppable.
* @param {Object} opts
* Configuration options to control how this droppable behaves.
*/
constructor(el, opts = {}) {
this.el = el;
this.opts = {
...opts,
};
this.id = el.dataset.containerId;
this.items = [];
this.children = [];
}
getId() {
return this.id;
}
getItems() {
return this.items;
}
getChildren() {
return this.children;
}
attachItem(item, pos) {
const el = item.getElement();
if ((pos || pos === 0) && this.items.length > pos) {
this.el.insertBefore(el, this.items[pos].getElement());
this.items.splice(pos, 0, el);
}
else {
this.el.appendChild(item.getElement());
this.items.push(item);
pos = this.items.length - 1;
}
item.attach(this, pos);
}
detachItem(item) {
for (let i = 0; i < this.items.length; ++i) {
if (this.items[i] === item) {
this.items.splice(i, 1);
break;
}
}
this.el.removeChild(item.getElement());
item.detach();
}
}
/**
* A element that is draggable and can get placed into {Droppable} objects.
*/
class Draggable {
/**
* Get the active dragging object instance, if there is a dragging action
* in progress. There will only be a single draggable actively being dragged
* at any given time.
*
* @return {Draggable|null}
* Return the draggable instance if there is one, otherwise return {null}.
*/
static get dragging() {
return this._dragging;
}
/**
* Get the currently active dragging tracking to this draggable object.
* This property is global because there should only be 1 active dragging
* activity for the entire application, even if it is accross multiple
* drag and drop sets.
*
* @param {Draggable|null} draggable
* Set the {Draggable} element as actively being dragged. Passing {null}
* as the parameter here is the same as unsetting cancelling any current
* dragging activity and clearing this property.
*/
static set dragging(draggable) {
if (this._dragging) {
const oldDrag = this._dragging;
oldDrag.cancelDrag(false);
}
this._dragging = draggable;
}
/**
* Construct a new draggable handler.
*
* @param {Element} el
* The element to attach the draggable behaviors to.
* @param {Object} opts
* The options for the draggable behaviors.
*/
constructor(el, opts = {}) {
this.el = el;
this.opts = {
inputSelector: 'input.drag-parent',
...opts,
};
this.parent = null;
this.pos = 0;
this.input = this.el.querySelector(this.opts.inputSelector);
}
getElement() {
return this.el;
}
attach(droppable, pos) {
this.parent = droppable;
this.pos = pos;
this.input.value = `${droppable.getId()}:${pos}`;
}
detach() {
this.parent = null;
this.pos = 0;
this.input.value = '';
}
/**
* Cancel the dragging action if it's been dragged.
*/
cancelDrag() {
if (this.placeholder) {
this.placeholder.parentNode.removeChild(this.placeholder);
}
}
}
// Export the drag and drop definitions to the Toolshed namespace.
Toolshed.Droppable = Droppable;
Toolshed.Draggable = Draggable;
})(Drupal);
