Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nestablejs

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nestablejs - npm Package Compare versions

Comparing version 0.0.6 to 0.0.7

docs/assets/css/attributes.css

1128

dist/nestable.js

@@ -8,45 +8,1089 @@ /*!

*
* Version: 0.0.6
* Version: 0.0.7
*
*/
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};$jscomp.arrayIterator=function(a){return{next:$jscomp.arrayIteratorImpl(a)}};$jscomp.makeIterator=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};
var DOM={select:function(a,b){b=void 0===b?document:b;return b.querySelector(a)},selectAll:function(a,b){b=void 0===b?document:b;return b.querySelectorAll(a)},children:function(a,b){for(var c=[],d=a.children,e=d.length,f=0;f<e;++f){var k=d[f];k.matches(b)&&c.push(k)}return c},parents:function(a,b){for(var c=[];a&&a!==document;a=a.parentNode)b?a.matches(b)&&c.push(a):c.push(a);return c},rect:function(a){var b=window,c=void 0!==b.pageYOffset?b.pageYOffset:(document.documentElement||document.body.parentNode||
document.body).scrollTop;a=a.getBoundingClientRect();return{left:a.left+b.pageXOffset,top:a.top+c,height:a.height,width:a.width}}},Nestable=function(a,b){this.defaultConfig={threshold:40,animation:0,collapseButtonContent:"\u2013",expandButtonContent:"+",includeContent:!1,maxDepth:3,showPlaceholderOnMove:!1,nodes:{list:"ol",item:"li"},classes:{list:"nst-list",item:"nst-item",content:"nst-content",parent:"nst-parent",dragging:"nst-dragging",handle:"nst-handle",placeholder:"nst-placeholder",container:"nst-container",
button:"nst-button",collapsed:"nst-collapsed",disabled:"nst-disabled",error:"nst-error",moving:"nst-moving"}};this.config=Object.assign({},this.defaultConfig,b);b&&(b.nodes&&(this.config.nodes=Object.assign({},this.defaultConfig.nodes,b.nodes)),b.classes&&(this.config.classes=Object.assign({},this.defaultConfig.classes,b.classes)));this.parent="string"===typeof a?DOM.select(a):a;if(!this.parent)return console.error("Node ("+a+") not found.");if(this.parent._nestable)return console.error("There is already a Nestable instance active on this node.");
this.initialised=!1;this.disabled=!0;this.last={x:0,y:0};this.init()};Nestable.prototype.on=function(a,b,c){"string"===typeof a?(this.listeners=this.listeners||{},this.listeners[a]=this.listeners[a]||[],this.listeners[a].push(b)):a.addEventListener(b,c,!1)};Nestable.prototype.off=function(a,b,c){"string"===typeof a?(this.listeners=this.listeners||{},!1!==a in this.listeners&&this.listeners[a].splice(this.listeners[a].indexOf(b),1)):a.removeEventListener(b,c)};
Nestable.prototype.emit=function(a){this.listeners=this.listeners||{};if(!1!==a in this.listeners)for(var b=0;b<this.listeners[a].length;b++)this.listeners[a][b].apply(this,Array.prototype.slice.call(arguments,1))};
Nestable.prototype.init=function(a){var b=this;if(!this.initialised){this.touch="ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch;a&&(this.config=Object.assign({},this.defaultConfig,a));this.dragDepth=0;this.parent.classList.add(this.config.classes.list);this.parent.classList.add(this.config.classes.parent);a=DOM.children(this.parent,this.config.nodes.item);a=$jscomp.makeIterator(a);for(var c=a.next();!c.done;c=a.next())this._nest(c.value);this.placeholder=document.createElement(this.config.nodes.item);
this.placeholder.classList.add(this.config.classes.placeholder);this._getData();this.parent._nestable=this;window._nestableInstances?(window._nestableInstances+=1,this.id=window._nestableInstances):this.id=window._nestableInstances=1;this.enable();this._getData();setTimeout(function(){b.emit("init")},10);this.initialised=!0}};
Nestable.prototype.destroy=function(){var a=this;if(this.initialised){this.initialised=!1;this.disable();this.parent.classList.remove(this.config.classes.list);this.parent.classList.remove(this.config.classes.parent);delete this.parent._nestable;window._nestableInstances&&--window._nestableInstances;var b=function(c){c.classList.remove(a.config.classes.item);c.classList.remove(a.config.classes.collapsed);var d=c.querySelector(a.config.nodes.list),e=c.querySelector("."+a.config.classes.content);c.querySelector("."+
a.config.classes.handle);var l=c.querySelector("."+a.config.classes.button);e.classList.contains(a.config.classes.handle);for(var g=document.createDocumentFragment(),h=e.childNodes.length-1;0<=h;h--)g.insertBefore(e.childNodes[h],g.firstChild);c.insertBefore(g,e);c.removeChild(e);if(d)for(d.classList.remove(a.config.classes.list),c.removeChild(l),c=DOM.children(d,a.config.nodes.item),c=$jscomp.makeIterator(c),d=c.next();!d.done;d=c.next())b(d.value)},c=DOM.children(this.parent,this.config.nodes.item);
c=$jscomp.makeIterator(c);for(var d=c.next();!d.done;d=c.next())b(d.value);this.emit("destroy",this.parent)}};
Nestable.prototype.bind=function(){this.events={start:this._onMouseDown.bind(this),move:this._onMouseMove.bind(this),end:this._onMouseUp.bind(this)};this.touch?(this.parent.addEventListener("touchstart",this.events.start,!1),document.addEventListener("touchmove",this.events.move,!1),document.addEventListener("touchend",this.events.end,!1),document.addEventListener("touchcancel",this.events.end,!1)):(this.parent.addEventListener("mousedown",this.events.start,!1),document.addEventListener("mousemove",
this.events.move,!1),document.addEventListener("mouseup",this.events.end,!1))};Nestable.prototype.unbind=function(){this.parent.removeEventListener("mousedown",this.events.start);document.removeEventListener("mousemove",this.events.move);document.removeEventListener("mouseup",this.events.end)};Nestable.prototype.enable=function(){this.disabled&&(this.bind(),this.parent.classList.remove(this.config.classes.disabled),this.disabled=!1)};
Nestable.prototype.disable=function(){this.disabled||(this.unbind(),this.parent.classList.add(this.config.classes.disabled),this.disabled=!0)};Nestable.prototype.serialise=function(){this.serialize()};Nestable.prototype.serialize=function(){return this._getData("data")};
Nestable.prototype.collapseAll=function(){var a=DOM.selectAll("."+this.config.classes.item,this.parent);a=$jscomp.makeIterator(a);for(var b=a.next();!b.done;b=a.next())if(b=b.value,!b.classList.contains(this.config.classes.collapsed)){var c=b.querySelector("."+this.config.classes.button);c&&this._collapseList(b,c)}};
Nestable.prototype.expandAll=function(){var a=DOM.selectAll("."+this.config.classes.item,this.parent);a=$jscomp.makeIterator(a);for(var b=a.next();!b.done;b=a.next())if(b=b.value,b.classList.contains(this.config.classes.collapsed)){var c=b.querySelector("."+this.config.classes.button);c&&this._expandList(b,c)}};Nestable.prototype.add=function(a,b){b||(b=this.parent);this._nest(a);if(b!==this.parent){var c=DOM.select(this.config.nodes.list,b);b=c?c:this._makeParent(b)}b.appendChild(a);this.update()};
Nestable.prototype.remove=function(a,b){b=void 0===b?!0:b;var c=a.closest(this.config.nodes.list);if(b)c.removeChild(a);else{var d=a.querySelector("."+this.config.classes.list);if(d&&(d=DOM.children(d,this.config.nodes.item),d.length)){for(var e=document.createDocumentFragment(),f=d.length-1;0<=f;f--)e.insertBefore(d[f],e.firstElementChild);c.replaceChild(e,a)}}this.update()};Nestable.prototype.update=function(){this._getData("nodes");this.emit("update")};
Nestable.prototype._nest=function(a){var b=a.querySelector("."+this.config.classes.handle),c=document.createElement("div");c.classList.add(this.config.classes.content);var d=a.childNodes;if(b)for(f=d.length-1;0<=f;f--){var e=d[f];e!==b&&e.nodeName.toLowerCase()!==this.config.nodes.list&&c.insertBefore(e,c.firstChild)}else{c.classList.add(this.config.classes.handle);for(var f=d.length-1;0<=f;f--)b=d[f],b.nodeName.toLowerCase()!==this.config.nodes.list&&c.insertBefore(b,c.firstChild)}a.classList.add(this.config.classes.item);
if(d=a.querySelector(this.config.nodes.list))for(a.insertBefore(c,d),c=this._makeParent(a),c=DOM.children(c,this.config.nodes.item),a.classList.contains(this.config.classes.collapsed)&&this._collapseList(a),a=$jscomp.makeIterator(c),c=a.next();!c.done;c=a.next())this._nest(c.value);else a.appendChild(c)};Nestable.prototype._isDisabled=function(a){var b=!1;a.classList.contains(this.config.classes.disabled)&&(b=!0);DOM.parents(a,"."+this.config.classes.disabled).length&&(b=!0);return b};
Nestable.prototype._getEvent=function(a){return this.touch?"touchend"===a.type?a.changedTouches[0]:a.touches[0]:a};
Nestable.prototype._onMouseDown=function(a){var b=this._getEvent(a),c=a.target.closest("."+this.config.classes.button),d=a.target.closest("."+this.config.classes.item);if(c)return this._toggleList(d,c);if(!a.target.closest("."+this.config.classes.handle))return!1;if(d){if(this._isDisabled(d))return!1;a.preventDefault();this.parent.classList.add(this.config.classes.moving);d.classList.add(this.config.classes.dragging);a=DOM.rect(d);this.origin={x:b.pageX,y:b.pageY,original:{x:b.pageX,y:b.pageY}};this.active=
{maxDepth:!1,collapsedParent:!1,disabledParent:!1,confinedParent:!1,node:d,rect:a,parent:!1};"nestableParent"in d.dataset&&(b=document.getElementById(d.dataset.nestableParent))&&(this.active.parent=b);this.placeholder.style.height=a.height+"px";this.config.showPlaceholderOnMove&&(this.placeholder.style.opacity=0);this.container||(this.container=document.createElement(this.config.nodes.list),this.container.classList.add(this.config.classes.list),this.container.classList.add(this.config.classes.container),
this.container.id="nestable_"+this.id);this.container.style.left=a.left+"px";this.container.style.top=a.top+"px";this.container.style.height=a.height+"px";this.container.style.width=a.width+"px";d.parentNode.insertBefore(this.placeholder,d);document.body.appendChild(this.container);this.container.appendChild(d);this.newParent=!1;this.dragDepth=0;d=DOM.selectAll(this.config.nodes.item,d);for(b=0;b<d.length;b++)a=DOM.parents(d[b],this.config.nodes.list).length-1,a>this.dragDepth&&(this.dragDepth=a);
this.emit("start",this.active)}};
Nestable.prototype._onMouseMove=function(a){if(this.active){this.config.showPlaceholderOnMove&&(this.placeholder.style.opacity=1);a=this._getEvent(a);var b=a.pageX-this.origin.x,c=a.pageY-this.origin.y;a.pageY>this.last.y?this.last.dirY=1:a.pageY<this.last.y&&(this.last.dirY=-1);a.pageX>this.last.x?this.last.dirX=1:a.pageX<this.last.x&&(this.last.dirX=-1);var d=!1;Math.abs(b)>Math.abs(c)?d="x":Math.abs(b)<Math.abs(c)&&(d="y");c=document.elementsFromPoint(a.pageX,a.pageY-(void 0!==window.pageYOffset?
window.pageYOffset:(document.documentElement||document.body.parentNode||document.body).scrollTop));if("x"===d)if(0<this.last.dirX&&b>this.config.threshold){if(d=this.placeholder.previousElementSibling)d.classList.contains(this.config.classes.collapsed)?this.active.collapsedParent||(this.emit("error.collapsed",this.active.node,d),this.active.collapsedParent=!0):this._isDisabled(d)?this.active.disabledParent||(this.emit("error.disabled"),this.active.disabledParent=!0):(c=DOM.parents(this.placeholder,
this.config.nodes.list).length+this.dragDepth<=this.config.maxDepth,b=d.querySelector(this.config.nodes.list),c?(this.active.maxDepth=!1,c=this.placeholder.closest("."+this.config.classes.list),b||(b=this._makeParent(d)),this._moveElement(this.placeholder,{parent:b,type:"appendChild"}),this.emit("nest",b,c),this.origin.x=a.pageX):this.active.maxDepth||(this.emit("error.maxdepth",this.active.node,this.config.maxDepth),this.active.maxDepth=!0))}else{if(0>this.last.dirX&&b<-this.config.threshold&&(this.active.maxDepth=
!1,this.active.disabledParent=!1,this.active.collapsedParent=!1,b=this.placeholder.closest(this.config.nodes.list),(d=b.closest(this.config.nodes.item))&&(1<b.childElementCount&&this.placeholder!==b.firstElementChild||2>b.childElementCount&&this.placeholder===b.firstElementChild))){b=d.nextElementSibling;c=this.placeholder.closest("."+this.config.classes.list);if(b){var e=b.closest(this.config.nodes.list);this._moveElement(this.placeholder,{parent:e,type:"insertBefore",sibling:b})}else this._moveElement(this.placeholder,
{parent:d.closest(this.config.nodes.list),type:"appendChild"});this.origin.x=a.pageX;this.emit("unnest",d,c)}}else for(b=$jscomp.makeIterator(c),c=b.next();!c.done;c=b.next())c=c.value,c!==this.active.node&&!this.active.node.contains(c)&&c.classList.contains(this.config.classes.content)&&((c=c.closest("."+this.config.classes.item))&&"y"===d&&(c.querySelector(this.config.nodes.list)&&!c.classList.contains(this.config.classes.collapsed)?0<this.last.dirY?this._moveElement(this.placeholder,{parent:c.lastElementChild,
type:"insertBefore",sibling:c.lastElementChild.firstElementChild,animatable:c.querySelector("."+this.config.classes.content)}):0>this.last.dirY&&this._moveElement(this.placeholder,{parent:c.parentNode,type:"insertBefore",sibling:c,animatable:c.querySelector("."+this.config.classes.content)}):0<this.last.dirY?(e=c.nextElementSibling)?this._moveElement(this.placeholder,{parent:c.parentNode,type:"insertBefore",sibling:e,animatable:c.querySelector("."+this.config.classes.content)}):this._moveElement(this.placeholder,
{parent:c.closest(this.config.nodes.list),type:"appendChild",animatable:c.querySelector("."+this.config.classes.content)}):0>this.last.dirY&&this._moveElement(this.placeholder,{parent:c.parentNode,type:"insertBefore",sibling:c,animatable:c.querySelector("."+this.config.classes.content)}),this.emit("reorder")),(c=c.closest("."+this.config.classes.parent))&&c!==this.parent&&c._nestable&&(this.newParent=c));this.placeholder.classList.toggle(this.config.classes.error,this.active.disabledParent||this.active.maxDepth||
this.active.collapsedParent||this.active.confinedParent);this.container.style.transform="translate3d("+(a.pageX-this.origin.original.x)+"px, "+(a.pageY-this.origin.original.y)+"px, 0)";this.lastParent=this.placeholder.parentNode;this.emit("move",this.active)}this.last={x:a.pageX,y:a.pageY}};
Nestable.prototype._moveElement=function(a,b){var c=!1,d=!1;if(this._isDisabled(b.parent))return!1;if(this.active.parent&&!DOM.parents(b.parent,"#"+this.active.parent.id).includes(this.active.parent))return this.active.confinedParent||(this.emit("error.confined",a,this.active.parent,b.parent),this.active.confinedParent=!0),!1;var e=a.closest(this.config.nodes.list);0<this.config.animation&&(c=DOM.rect(this.placeholder),b.animatable&&(d=DOM.rect(b.animatable)));"insertBefore"===b.type?b.parent.insertBefore(a,
b.sibling):"appendChild"===b.type&&b.parent.appendChild(a);e.childElementCount||this._unmakeParent(e.parentNode);this.emit("order.change",this.active.node,b.parent,e);0<this.config.animation&&(this._animateElement(this.placeholder,c),b.animatable&&d&&this._animateElement(b.animatable,d))};
Nestable.prototype._animateElement=function(a,b){var c=a.style,d=DOM.rect(a);c.transform="translate3d("+(b.left-d.left)+"px, "+(b.top-d.top)+"px, 0px)";this._repaint(a);c.transform="translate3d(0px, 0px, 0px)";c.transition="transform "+this.config.animation+"ms";setTimeout(function(){c.transform="";c.transition=""},this.config.animation)};Nestable.prototype._repaint=function(a){return a.offsetHeight};
Nestable.prototype._onMouseUp=function(a){this.active&&(this.config.showPlaceholderOnMove&&(this.placeholder.style.opacity=0),this._getEvent(a),a=DOM.rect(this.active.node),this.container.removeAttribute("style"),this.parent.classList.remove(this.config.classes.moving),this.placeholder.parentNode.replaceChild(this.active.node,this.placeholder),this._animateElement(this.active.node,a),this.placeholder.classList.remove(this.config.classes.error),this.active.node.classList.remove(this.config.classes.dragging),
this.active=!1,document.body.removeChild(this.container),this._getData(),this.newParent&&this.newParent._nestable._getData(),this.emit("stop",this.data),this.update())};Nestable.prototype._toggleList=function(a,b){a.classList.contains(this.config.classes.collapsed)?this._expandList(a,b):this._collapseList(a,b)};Nestable.prototype._collapseList=function(a,b){b||(b=a.querySelector("."+this.config.classes.button));b.textContent=this.config.expandButtonContent;a.classList.add(this.config.classes.collapsed)};
Nestable.prototype._expandList=function(a,b){b||(b=a.querySelector("."+this.config.classes.button));b.textContent=this.config.collapseButtonContent;a.classList.remove(this.config.classes.collapsed)};
Nestable.prototype._makeParent=function(a){var b=a.querySelector(this.config.nodes.list);b?b.classList.add(this.config.classes.list):(b=document.createElement(this.config.nodes.list),b.classList.add(this.config.classes.list),a.appendChild(b));var c=document.createElement("button");c.classList.add(this.config.classes.button);c.type="button";c.textContent=this.config.collapseButtonContent;a.insertBefore(c,a.firstElementChild);return b};
Nestable.prototype._unmakeParent=function(a){var b=a.querySelector(this.config.nodes.list),c=a.querySelector("button");b&&a.removeChild(b);c&&a.removeChild(c)};
Nestable.prototype._getData=function(a){var b=this;a=void 0===a?"nodes":a;var c=[],d=function(c){var e=[];DOM.children(c,b.config.nodes.item).forEach(function(c){var f={};if("nodes"===a)f.node=c;else if(f.data=Object.assign({},c.dataset),b.config.includeContent){var g=c.querySelector("."+b.config.classes.content);g&&(f.content=g.innerHTML)}if(c=c.querySelector(b.config.nodes.list))f.children=d(c);e.push(f)});return e};c=d(this.parent);"nodes"===a&&(this.data=c);return c};
const DOM = {
select: (selector, parent = document) => {
return parent.querySelector(selector);
},
selectAll: (selector, parent = document) => {
return parent.querySelectorAll(selector);
},
/**
* Get an elements children that match the selector
* @param {Node} elem The base element
* @param {String} selector CSS3 selector string
* @return {Array}
*/
children: (elem, selector) => {
const arr = [];
const children = elem.children;
const l = children.length;
for (let i = 0; i < l; ++i) {
const child = children[i];
if (child.matches(selector)) {
arr.push(child);
}
}
return arr;
},
/**
* Get all DOM element up the tree that match the selector
* @param {Node} elem The base element
* @param {String} selector CSS3 selector string
* @return {Array}
*/
parents: (elem, selector) => {
// Set up a parent array
var parents = [];
// Push each parent element to the array
for (; elem && elem !== document; elem = elem.parentNode) {
if (selector) {
if (elem.matches(selector)) {
parents.push(elem);
}
continue;
}
parents.push(elem);
}
// Return our parent array
return parents;
},
/**
* Get an element's DOMRect relative to the document instead of the viewport.
* @param {Object} el HTMLElement
* @return {Object} Formatted DOMRect copy
*/
rect(el) {
var w = window,
st = (w.pageYOffset !== undefined) ? w.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop,
o = el.getBoundingClientRect(),
x = w.pageXOffset,
y = st;
return {
left: o.left + x,
top: o.top + y,
height: o.height,
width: o.width
};
}
}
class Nestable {
constructor(list, options) {
this.defaultConfig = {
threshold: 40,
animation: 0,
collapseButtonContent: "–",
expandButtonContent: "+",
includeContent: false,
maxDepth: 3,
showPlaceholderOnMove: false,
nodes: {
list: "ol",
item: "li"
},
classes: {
list: "nst-list",
item: "nst-item",
content: "nst-content",
parent: "nst-parent",
dragging: "nst-dragging",
handle: "nst-handle",
placeholder: "nst-placeholder",
container: "nst-container",
button: "nst-button",
collapsed: "nst-collapsed",
disabled: "nst-disabled",
error: "nst-error",
moving: "nst-moving",
},
};
this.config = Object.assign({}, this.defaultConfig, options);
if (options) {
if (options.nodes) {
this.config.nodes = Object.assign({}, this.defaultConfig.nodes, options.nodes);
}
if (options.classes) {
this.config.classes = Object.assign({}, this.defaultConfig.classes, options.classes);
}
}
this.parent = typeof list === "string" ? DOM.select(list) : list;
if (!this.parent) {
return console.error(`Node (${list}) not found.`);
}
if (this.parent._nestable) {
return console.error("There is already a Nestable instance active on this node.");
}
this.initialised = false;
this.disabled = true;
this.last = {
x: 0,
y: 0
};
this.init();
}
/**
* Add custom event listener
* @param {String} event
* @param {Function} callback
* @return {Void}
*/
on(listener, fn, capture) {
if (typeof listener === "string") {
this.listeners = this.listeners || {};
this.listeners[listener] = this.listeners[listener] || [];
this.listeners[listener].push(fn);
} else {
arguments[0].addEventListener(arguments[1], arguments[2], false);
}
}
/**
* Remove custom listener listener
* @param {String} listener
* @param {Function} callback
* @return {Void}
*/
off(listener, fn) {
if (typeof listener === "string") {
this.listeners = this.listeners || {};
if (listener in this.listeners === false) return;
this.listeners[listener].splice(this.listeners[listener].indexOf(fn), 1);
} else {
arguments[0].removeEventListener(arguments[1], arguments[2]);
}
}
/**
* Fire custom listener
* @param {String} listener
* @return {Void}
*/
emit(listener) {
this.listeners = this.listeners || {};
if (listener in this.listeners === false) return;
for (var i = 0; i < this.listeners[listener].length; i++) {
this.listeners[listener][i].apply(this, Array.prototype.slice.call(arguments, 1));
}
}
init(options) {
if (!this.initialised) {
this.touch =
"ontouchstart" in window ||
(window.DocumentTouch && document instanceof DocumentTouch);
if (options) {
this.config = Object.assign({}, this.defaultConfig, options);
}
this.dragDepth = 0;
this.parent.classList.add(this.config.classes.list);
this.parent.classList.add(this.config.classes.parent);
const items = DOM.children(this.parent, this.config.nodes.item);
for (const item of items) {
this._nest(item);
}
this.placeholder = document.createElement(this.config.nodes.item);
this.placeholder.classList.add(this.config.classes.placeholder);
this._getData();
this.parent._nestable = this;
if (!window._nestableInstances) {
window._nestableInstances = 1;
this.id = 1;
} else {
window._nestableInstances += 1;
this.id = window._nestableInstances
}
this.enable();
this._getData();
setTimeout(() => {
this.emit("init");
}, 10);
this.initialised = true;
}
}
destroy() {
if (this.initialised) {
this.initialised = false;
this.disable();
this.parent.classList.remove(this.config.classes.list);
this.parent.classList.remove(this.config.classes.parent);
delete(this.parent._nestable);
if (window._nestableInstances) {
window._nestableInstances -= 1;
}
const destroyItem = (item) => {
item.classList.remove(this.config.classes.item);
item.classList.remove(this.config.classes.collapsed);
const listEl = item.querySelector(this.config.nodes.list);
const contentEl = item.querySelector(`.${this.config.classes.content}`);
const handleEl = item.querySelector(`.${this.config.classes.handle}`);
const buttonEl = item.querySelector(`.${this.config.classes.button}`);
// default handle is also the content container
const defaultHandle = contentEl.classList.contains(this.config.classes.handle);
const div = document.createDocumentFragment();
for (var i = contentEl.childNodes.length - 1; i >= 0; i--) {
div.insertBefore(contentEl.childNodes[i], div.firstChild);
}
item.insertBefore(div, contentEl)
item.removeChild(contentEl);
if (listEl) {
listEl.classList.remove(this.config.classes.list);
item.removeChild(buttonEl);
const items = DOM.children(listEl, this.config.nodes.item);
for (const item of items) {
destroyItem(item);
}
}
};
const items = DOM.children(this.parent, this.config.nodes.item);
for (const item of items) {
destroyItem(item);
}
this.emit("destroy", this.parent);
}
}
bind() {
this.events = {
start: this._onMouseDown.bind(this),
move: this._onMouseMove.bind(this),
end: this._onMouseUp.bind(this),
};
if (this.touch) {
this.parent.addEventListener("touchstart", this.events.start, false);
document.addEventListener("touchmove", this.events.move, false);
document.addEventListener("touchend", this.events.end, false);
document.addEventListener("touchcancel", this.events.end, false);
} else {
this.parent.addEventListener("mousedown", this.events.start, false);
document.addEventListener("mousemove", this.events.move, false);
document.addEventListener("mouseup", this.events.end, false);
}
}
unbind() {
this.parent.removeEventListener("mousedown", this.events.start);
document.removeEventListener("mousemove", this.events.move);
document.removeEventListener("mouseup", this.events.end);
}
enable() {
if (this.disabled) {
this.bind();
this.parent.classList.remove(this.config.classes.disabled);
this.disabled = false;
}
}
disable() {
if (!this.disabled) {
this.unbind();
this.parent.classList.add(this.config.classes.disabled);
this.disabled = true;
}
}
serialise() {
this.serialize();
}
serialize() {
return this._getData("data");
}
collapseAll() {
const items = DOM.selectAll(`.${this.config.classes.item}`, this.parent);
for (const item of items) {
if (!item.classList.contains(this.config.classes.collapsed)) {
const btn = item.querySelector(`.${this.config.classes.button}`);
if (btn) {
this._collapseList(item, btn);
}
}
}
}
expandAll() {
const items = DOM.selectAll(`.${this.config.classes.item}`, this.parent);
for (const item of items) {
if (item.classList.contains(this.config.classes.collapsed)) {
const btn = item.querySelector(`.${this.config.classes.button}`);
if (btn) {
this._expandList(item, btn);
}
}
}
}
add(element, parent) {
if (!parent) {
parent = this.parent;
}
this._nest(element);
if (parent !== this.parent) {
const listEl = DOM.select(this.config.nodes.list, parent);
if (!listEl) {
parent = this._makeParent(parent);
} else {
parent = listEl;
}
}
parent.appendChild(element);
this.update();
}
remove(element, removeChildElements = true) {
const parentEl = element.closest(this.config.nodes.list);
if (!removeChildElements) {
const childList = element.querySelector(`.${this.config.classes.list}`);
if (childList) {
const childElements = DOM.children(childList, this.config.nodes.item);
if (childElements.length) {
const frag = document.createDocumentFragment();
for (var i = childElements.length - 1; i >= 0; i--) {
const childElement = childElements[i];
frag.insertBefore(childElement, frag.firstElementChild);
}
parentEl.replaceChild(frag, element);
}
}
} else {
parentEl.removeChild(element);
}
this.update();
}
update() {
this._getData("nodes");
this.emit("update");
}
_nest(el) {
const handle = el.querySelector(`.${this.config.classes.handle}`);
const content = document.createElement("div");
content.classList.add(this.config.classes.content);
const nodes = el.childNodes;
if (!handle) {
content.classList.add(this.config.classes.handle);
for (var i = nodes.length - 1; i >= 0; i--) {
const node = nodes[i];
if (node.nodeName.toLowerCase() !== this.config.nodes.list) {
content.insertBefore(node, content.firstChild);
}
}
} else {
for (var i = nodes.length - 1; i >= 0; i--) {
const node = nodes[i];
if (node !== handle && node.nodeName.toLowerCase() !== this.config.nodes.list) {
content.insertBefore(node, content.firstChild);
}
}
}
el.classList.add(this.config.classes.item);
const list = el.querySelector(this.config.nodes.list);
if (list) {
el.insertBefore(content, list);
const parent = this._makeParent(el);
const items = DOM.children(parent, this.config.nodes.item);
if (el.classList.contains(this.config.classes.collapsed)) {
this._collapseList(el);
}
for (const i of items) {
this._nest(i);
}
} else {
el.appendChild(content);
}
}
_isDisabled(item) {
// item has the [data-nestable-disabled] attribute
if ("nestableDisabled" in item.dataset) {
if (!item.dataset.nestableDisabled.length || item.dataset.nestableDisabled !== "false") {
return true;
}
}
if (item.classList.contains(this.config.classes.disabled)) {
return true;
}
const listEls = DOM.parents(item, `.${this.config.classes.disabled}`);
if (listEls.length) {
return true;
}
return false;
}
/**
* Get event
* @return {Object}
*/
_getEvent(e) {
if (this.touch) {
if (e.type === "touchend") {
return e.changedTouches[0];
}
return e.touches[0];
}
return e;
}
_onMouseDown(e) {
const evt = this._getEvent(e);
const button = e.target.closest(`.${this.config.classes.button}`);
const item = e.target.closest(`.${this.config.classes.item}`);
if (button) {
return this._toggleList(item, button);
}
const handle = e.target.closest(`.${this.config.classes.handle}`);
if (!handle) {
return false;
}
if (item) {
if (this._isDisabled(item)) {
return false;
}
e.preventDefault();
this.parent.classList.add(this.config.classes.moving);
item.classList.add(this.config.classes.dragging);
const rect = DOM.rect(item);
this.origin = {
x: evt.pageX,
y: evt.pageY,
original: {
x: evt.pageX,
y: evt.pageY,
}
};
this.active = {
maxDepth: false,
collapsedParent: false,
disabledParent: false,
confinedParent: false,
node: item,
rect: rect,
parent: false,
axis: false,
};
// item has the [data-nestable-parent] attribute
if ("nestableParent" in item.dataset) {
const parent = document.getElementById(item.dataset.nestableParent);
if (parent) {
this.active.parent = parent;
}
}
// item has the [data-nestable-axis] attribute
if ("nestableAxis" in item.dataset) {
const axis = item.dataset.nestableAxis;
if (axis === "x") {
this.active.axis = "x";
} else if (axis === "y") {
this.active.axis = "y";
}
}
this.placeholder.style.height = `${rect.height}px`;
// this.placeholder.style.width = `${rect.width}px`;
if (this.config.showPlaceholderOnMove) {
this.placeholder.style.opacity = 0;
}
if (!this.container) {
this.container = document.createElement(this.config.nodes.list);
this.container.classList.add(this.config.classes.list);
this.container.classList.add(this.config.classes.container);
this.container.id = `nestable_${this.id}`;
}
this.container.style.left = `${rect.left}px`;
this.container.style.top = `${rect.top}px`;
this.container.style.height = `${rect.height}px`;
this.container.style.width = `${rect.width}px`;
item.parentNode.insertBefore(this.placeholder, item);
document.body.appendChild(this.container);
this.container.appendChild(item);
this.newParent = false;
this.dragDepth = 0;
// total depth of dragging item
const items = DOM.selectAll(this.config.nodes.item, item);
for (let i = 0; i < items.length; i++) {
const depth = DOM.parents(items[i], this.config.nodes.list).length - 1;
if (depth > this.dragDepth) {
this.dragDepth = depth;
}
}
this.emit("start", this.active);
}
}
_onMouseMove(e) {
if (this.active) {
if (this.config.showPlaceholderOnMove) {
this.placeholder.style.opacity = 1;
}
e = this._getEvent(e);
let x = e.pageX - this.origin.x;
let y = e.pageY - this.origin.y;
if (e.pageY > this.last.y) {
this.last.dirY = 1;
} else if (e.pageY < this.last.y) {
this.last.dirY = -1;
}
if (e.pageX > this.last.x) {
this.last.dirX = 1;
} else if (e.pageX < this.last.x) {
this.last.dirX = -1;
}
let movement = false;
if (Math.abs(x) > Math.abs(y)) {
movement = "x";
} else if (Math.abs(x) < Math.abs(y)) {
movement = "y";
}
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
const elements = document.elementsFromPoint(e.pageX, e.pageY - scrollTop);
if (movement === "x" && this.active.axis !== "y") {
if (this.last.dirX > 0 && x > this.config.threshold) { // moving right
const prevEl = this.placeholder.previousElementSibling;
if (prevEl) {
if (prevEl.classList.contains(this.config.classes.collapsed)) {
if (!this.active.collapsedParent) {
this.emit("error.collapsed", this.active.node, prevEl);
this.active.collapsedParent = true;
}
} else {
const disabled = this._isDisabled(prevEl);
if (!disabled) {
const depth = DOM.parents(this.placeholder, this.config.nodes.list).length;
let allowNesting = depth + this.dragDepth <= this.config.maxDepth;
let parentEl = prevEl.querySelector(this.config.nodes.list);
if (allowNesting) {
this.active.maxDepth = false;
const oldParent = this.placeholder.closest(`.${this.config.classes.list}`);
if (!parentEl) {
parentEl = this._makeParent(prevEl);
}
this._moveElement(this.placeholder, {
parent: parentEl,
type: "appendChild",
});
this.emit("nest", parentEl, oldParent);
this.origin.x = e.pageX;
} else {
if (!this.active.maxDepth) {
this.emit("error.maxdepth", this.active.node, this.config.maxDepth);
this.active.maxDepth = true;
}
}
} else {
if (!this.active.disabledParent) {
this.emit("error.disabled");
this.active.disabledParent = true;
}
}
}
}
} else if (this.last.dirX < 0 && x < -this.config.threshold) { // moving left
this.active.maxDepth = false;
this.active.disabledParent = false;
this.active.collapsedParent = false;
// this.active.confinedParent = false;
const listEl = this.placeholder.closest(this.config.nodes.list);
const parentEl = listEl.closest(this.config.nodes.item);
if (parentEl &&
((listEl.childElementCount > 1 && this.placeholder !== listEl.firstElementChild) || listEl.childElementCount < 2 && this.placeholder === listEl.firstElementChild)) {
const nextEl = parentEl.nextElementSibling;
const oldParent = this.placeholder.closest(`.${this.config.classes.list}`);
if (nextEl) {
const list = nextEl.closest(this.config.nodes.list);
this._moveElement(this.placeholder, {
parent: list,
type: "insertBefore",
sibling: nextEl
});
this.origin.x = e.pageX;
} else {
this._moveElement(this.placeholder, {
parent: parentEl.closest(this.config.nodes.list),
type: "appendChild",
});
this.origin.x = e.pageX;
}
this.emit("unnest", parentEl, oldParent);
}
}
} else {
// check if we're over a valid item
for (const element of elements) {
const moveY = element !== this.active.node &&
!this.active.node.contains(element) &&
element.classList.contains(this.config.classes.content) &&
this.active.axis !== "x";
if (moveY) {
const item = element.closest(`.${this.config.classes.item}`);
if (item) {
if (movement === "y") {
const childListEl = item.querySelector(this.config.nodes.list);
if (childListEl && !item.classList.contains(this.config.classes.collapsed)) { // item is parent
if (this.last.dirY > 0) { // moving item down
this._moveElement(this.placeholder, {
parent: item.lastElementChild,
type: "insertBefore",
sibling: item.lastElementChild.firstElementChild,
animatable: item.querySelector(`.${this.config.classes.content}`)
});
} else if (this.last.dirY < 0) { // moving item up
this._moveElement(this.placeholder, {
parent: item.parentNode,
type: "insertBefore",
sibling: item,
animatable: item.querySelector(`.${this.config.classes.content}`)
});
}
this.emit("reorder");
} else { // item is not a parent
if (this.last.dirY > 0) { // moving item down
const nextEl = item.nextElementSibling;
if (nextEl) { // item has an item below it
this._moveElement(this.placeholder, {
parent: item.parentNode,
type: "insertBefore",
sibling: nextEl,
animatable: item.querySelector(`.${this.config.classes.content}`)
});
} else { // item is last in list
this._moveElement(this.placeholder, {
parent: item.closest(this.config.nodes.list),
type: "appendChild",
animatable: item.querySelector(`.${this.config.classes.content}`)
});
}
} else if (this.last.dirY < 0) { // moving item up
this._moveElement(this.placeholder, {
parent: item.parentNode,
type: "insertBefore",
sibling: item,
animatable: item.querySelector(`.${this.config.classes.content}`)
});
}
this.emit("reorder");
}
}
}
const parentEl = item.closest(`.${this.config.classes.parent}`);
if (parentEl) {
if (parentEl !== this.parent) {
if (parentEl._nestable) {
this.newParent = parentEl;
}
}
}
}
}
}
this.placeholder.classList.toggle(this.config.classes.error,
this.active.disabledParent ||
this.active.maxDepth ||
this.active.collapsedParent ||
this.active.confinedParent);
let mx = e.pageX - this.origin.original.x;
let my = e.pageY - this.origin.original.y;
// item movement is confined
if (this.active.axis) {
if (this.active.axis === "x") {
my = 0;
} else if (this.active.axis === "y") {
mx = 0;
}
}
this.container.style.transform = `translate3d(${mx}px, ${my}px, 0)`;
this.lastParent = this.placeholder.parentNode;
this.emit("move", this.active);
}
this.last = {
x: e.pageX,
y: e.pageY
};
}
_moveElement(el, type) {
let ppos = false;
let ipos = false;
// prevent moving if item has disabled parents
if (this._isDisabled(type.parent)) {
return false;
}
// prevent moving if item is confined to parent with data-nestable-parent
if (this.active.parent) {
if (!DOM.parents(type.parent, `#${this.active.parent.id}`).includes(this.active.parent)) {
if (!this.active.confinedParent) {
this.emit("error.confined", el, this.active.parent, type.parent);
this.active.confinedParent = true;
}
return false;
}
}
let listEl = el.closest(this.config.nodes.list);
// if animation is enabled, we need to get the original position of the element first
if (this.config.animation > 0) {
ppos = DOM.rect(this.placeholder);
if (type.animatable) {
ipos = DOM.rect(type.animatable)
}
}
if (type.type === "insertBefore") {
type.parent.insertBefore(el, type.sibling);
} else if (type.type === "appendChild") {
type.parent.appendChild(el);
}
if (!listEl.childElementCount) {
this._unmakeParent(listEl.parentNode);
}
this.emit("order.change", this.active.node, type.parent, listEl);
// animate the elements
if (this.config.animation > 0) {
this._animateElement(this.placeholder, ppos);
if (type.animatable && ipos) {
this._animateElement(type.animatable, ipos);
}
}
}
_animateElement(el, obj) {
// Animate an element's change in position
// caused by a change in the DOM order
let css = el.style;
// Get the node's positon AFTER the change
let r = DOM.rect(el);
// Calculate the difference in position
let x = obj.left - r.left;
let y = obj.top - r.top;
// Move the node to it's original position before the DOM change
css.transform = `translate3d(${x}px, ${y}px, 0px)`;
// css.zIndex = 10000;
// Trigger a repaint so the next bit works
this._repaint(el);
// Reset the transform, but add a transition so it's smooth
css.transform = `translate3d(0px, 0px, 0px)`;
css.transition = `transform ${this.config.animation}ms`;
// Reset the style
setTimeout(function() {
// console.log("foo")
// css.zIndex = "";
css.transform = "";
css.transition = "";
}, this.config.animation);
}
_repaint(el) {
return el.offsetHeight;
}
_onMouseUp(e) {
if (this.active) {
if (this.config.showPlaceholderOnMove) {
this.placeholder.style.opacity = 0;
}
e = this._getEvent(e);
const prect = DOM.rect(this.active.node);
// this.active.node.removeAttribute("style");
this.container.removeAttribute("style");
this.parent.classList.remove(this.config.classes.moving);
this.placeholder.parentNode.replaceChild(this.active.node, this.placeholder);
this._animateElement(this.active.node, prect);
this.placeholder.classList.remove(this.config.classes.error);
this.active.node.classList.remove(this.config.classes.dragging);
this.active = false;
document.body.removeChild(this.container);
this._getData();
if (this.newParent) {
this.newParent._nestable._getData();
}
this.emit("stop", this.data);
this.update();
}
}
_toggleList(item, btn) {
if (!item.classList.contains(this.config.classes.collapsed)) {
this._collapseList(item, btn);
} else {
this._expandList(item, btn);
}
}
_collapseList(item, btn) {
if (!btn) {
btn = item.querySelector(`.${this.config.classes.button}`)
}
btn.textContent = this.config.expandButtonContent;
item.classList.add(this.config.classes.collapsed);
}
_expandList(item, btn) {
if (!btn) {
btn = item.querySelector(`.${this.config.classes.button}`)
}
btn.textContent = this.config.collapseButtonContent;
item.classList.remove(this.config.classes.collapsed);
}
_makeParent(el) {
let parentEl = el.querySelector(this.config.nodes.list);
if (!parentEl) {
parentEl = document.createElement(this.config.nodes.list);
parentEl.classList.add(this.config.classes.list);
el.appendChild(parentEl);
} else {
parentEl.classList.add(this.config.classes.list);
}
const button = document.createElement("button");
button.classList.add(this.config.classes.button);
button.type = "button";
button.textContent = this.config.collapseButtonContent;
el.insertBefore(button, el.firstElementChild);
return parentEl;
}
_unmakeParent(el) {
const list = el.querySelector(this.config.nodes.list);
const btn = el.querySelector("button");
if (list) {
el.removeChild(list);
}
if (btn) {
el.removeChild(btn);
}
return
}
_getData(type = "nodes") {
let data = [];
const step = (level) => {
const array = [];
const items = DOM.children(level, this.config.nodes.item);
items.forEach((li) => {
const item = {};
if (type === "nodes") {
item.node = li;
} else {
item.data = Object.assign({}, li.dataset);
if (this.config.includeContent) {
const content = li.querySelector(`.${this.config.classes.content}`);
if (content) {
item.content = content.innerHTML;
}
}
}
const sub = li.querySelector(this.config.nodes.list);
if (sub) {
item.children = step(sub);
}
array.push(item);
});
return array;
};
data = step(this.parent);
if (type === "nodes") {
this.data = data;
}
return data;
}
}

@@ -123,2 +123,3 @@ /* global hljs */

<li><a href="https://mobius1.github.io/NestableJS/options.html">Options</a></li>
<li><a href="https://mobius1.github.io/NestableJS/data-attributes.html">Data Attributes</a></li>
<li><a href="https://mobius1.github.io/NestableJS/public-methods.html">Public Methods</a></li>

@@ -158,2 +159,5 @@ <li><a href="https://mobius1.github.io/NestableJS/events.html">Events</a></li>

<li><a href="https://mobius1.github.io/NestableJS/api/events/stop.html">stop</a></li>
<li><a href="https://mobius1.github.io/NestableJS/api/events/nest.html">nest</a></li>
<li><a href="https://mobius1.github.io/NestableJS/api/events/unnest.html">unnest</a></li>
<li><a href="https://mobius1.github.io/NestableJS/api/events/reorder.html">reorder</a></li>
<li><a href="https://mobius1.github.io/NestableJS/api/events/error.maxdepth.html">error.maxdepth</a></li>

@@ -160,0 +164,0 @@ <li><a href="https://mobius1.github.io/NestableJS/api/events/error.disabled.html">error.disabled</a></li>

2

package.json
{
"name": "nestablejs",
"version": "0.0.6",
"version": "0.0.7",
"description": "NestableJS is a javascript library for creating drag & drop heirarchical lists.",

@@ -5,0 +5,0 @@ "main": "dist/nestable.js",

@@ -6,5 +6,5 @@ import DOM from "./utils/DOM.js";

constructor(list, options) {
super();
this.defaultConfig = {

@@ -38,45 +38,48 @@ threshold: 40,

};
this.config = Object.assign({}, this.defaultConfig, options);
if ( options ) {
if ( options.nodes ) {
this.config.nodes = Object.assign({}, this.defaultConfig.nodes, options.nodes);
}
if ( options.classes ) {
this.config.classes = Object.assign({}, this.defaultConfig.classes, options.classes);
if (options) {
if (options.nodes) {
this.config.nodes = Object.assign({}, this.defaultConfig.nodes, options.nodes);
}
}
if (options.classes) {
this.config.classes = Object.assign({}, this.defaultConfig.classes, options.classes);
}
}
this.parent = typeof list === "string" ? DOM.select(list) : list;
if ( !this.parent ) {
if (!this.parent) {
return console.error(`Node (${list}) not found.`);
}
}
if ( this.parent._nestable ) {
if (this.parent._nestable) {
return console.error("There is already a Nestable instance active on this node.");
}
}
this.initialised = false;
this.disabled = true;
this.last = { x: 0, y: 0 };
this.last = {
x: 0,
y: 0
};
this.init();
}
init(options) {
if ( !this.initialised ) {
if (!this.initialised) {
this.touch =
"ontouchstart" in window ||
(window.DocumentTouch && document instanceof DocumentTouch);
if ( options ) {
"ontouchstart" in window ||
(window.DocumentTouch && document instanceof DocumentTouch);
if (options) {
this.config = Object.assign({}, this.defaultConfig, options);
}
this.dragDepth = 0;
this.dragDepth = 0;
this.parent.classList.add(this.config.classes.list);

@@ -87,3 +90,3 @@ this.parent.classList.add(this.config.classes.parent);

const items = DOM.children(this.parent, this.config.nodes.item);
for ( const item of items ) {
for (const item of items) {
this._nest(item);

@@ -99,3 +102,3 @@ }

if ( !window._nestableInstances ) {
if (!window._nestableInstances) {
window._nestableInstances = 1;

@@ -111,19 +114,19 @@

this.enable();
this._getData();
setTimeout(() => {
this.emit("init");
}, 10);
this.initialised = true;
}
}
destroy() {
if ( this.initialised ) {
if (this.initialised) {
this.initialised = false;
this.disable();

@@ -133,13 +136,13 @@

this.parent.classList.remove(this.config.classes.parent);
delete(this.parent._nestable);
if ( window._nestableInstances ) {
if (window._nestableInstances) {
window._nestableInstances -= 1;
}
const destroyItem = (item) => {
item.classList.remove(this.config.classes.item);
item.classList.remove(this.config.classes.collapsed);
const listEl = item.querySelector(this.config.nodes.list);

@@ -149,6 +152,6 @@ const contentEl = item.querySelector(`.${this.config.classes.content}`);

const buttonEl = item.querySelector(`.${this.config.classes.button}`);
// default handle is also the content container
const defaultHandle = contentEl.classList.contains(this.config.classes.handle);
const div = document.createDocumentFragment();

@@ -159,13 +162,13 @@

}
item.insertBefore(div, contentEl)
item.insertBefore(div, contentEl)
item.removeChild(contentEl);
if ( listEl ) {
if (listEl) {
listEl.classList.remove(this.config.classes.list);
item.removeChild(buttonEl);
const items = DOM.children(listEl, this.config.nodes.item);
for ( const item of items ) {
for (const item of items) {
destroyItem(item);

@@ -175,13 +178,13 @@ }

};
const items = DOM.children(this.parent, this.config.nodes.item);
for ( const item of items ) {
for (const item of items) {
destroyItem(item);
}
this.emit("destroy", this.parent);
}
}
}
bind() {

@@ -193,3 +196,3 @@ this.events = {

};
if (this.touch) {

@@ -206,3 +209,3 @@ this.parent.addEventListener("touchstart", this.events.start, false);

}
unbind() {

@@ -213,38 +216,38 @@ this.parent.removeEventListener("mousedown", this.events.start);

}
enable() {
if ( this.disabled ) {
if (this.disabled) {
this.bind();
this.parent.classList.remove(this.config.classes.disabled);
this.disabled = false;
}
}
disable() {
if ( !this.disabled ) {
if (!this.disabled) {
this.unbind();
this.parent.classList.add(this.config.classes.disabled);
this.disabled = true;
}
}
serialise() {
this.serialize();
}
serialize() {
return this._getData("data");
}
}
collapseAll() {
const items = DOM.selectAll(`.${this.config.classes.item}`, this.parent);
for ( const item of items ) {
if ( !item.classList.contains(this.config.classes.collapsed) ) {
for (const item of items) {
if (!item.classList.contains(this.config.classes.collapsed)) {
const btn = item.querySelector(`.${this.config.classes.button}`);
if ( btn ) {
if (btn) {
this._collapseList(item, btn);

@@ -255,10 +258,10 @@ }

}
expandAll() {
const items = DOM.selectAll(`.${this.config.classes.item}`, this.parent);
for ( const item of items ) {
if ( item.classList.contains(this.config.classes.collapsed) ) {
for (const item of items) {
if (item.classList.contains(this.config.classes.collapsed)) {
const btn = item.querySelector(`.${this.config.classes.button}`);
if ( btn ) {
if (btn) {
this._expandList(item, btn);

@@ -269,15 +272,15 @@ }

}
add(element, parent) {
if ( !parent ) {
if (!parent) {
parent = this.parent;
}
this._nest(element);
if ( parent !== this.parent ) {
if (parent !== this.parent) {
const listEl = DOM.select(this.config.nodes.list, parent);
if ( !listEl ) {
if (!listEl) {
parent = this._makeParent(parent);

@@ -288,20 +291,20 @@ } else {

}
parent.appendChild(element);
this.update();
}
remove(element, removeChildElements = true) {
const parentEl = element.closest(this.config.nodes.list);
if ( !removeChildElements ) {
if (!removeChildElements) {
const childList = element.querySelector(`.${this.config.classes.list}`);
if ( childList ) {
if (childList) {
const childElements = DOM.children(childList, this.config.nodes.item);
if ( childElements.length ) {
if (childElements.length) {
const frag = document.createDocumentFragment();

@@ -311,4 +314,4 @@

const childElement = childElements[i];
frag.insertBefore(childElement, frag.firstElementChild);
}
frag.insertBefore(childElement, frag.firstElementChild);
}
parentEl.replaceChild(frag, element);

@@ -320,12 +323,12 @@ }

}
this.update();
}
update() {
this._getData("nodes");
this.emit("update");
}
_nest(el) {

@@ -339,3 +342,3 @@ const handle = el.querySelector(`.${this.config.classes.handle}`);

if ( !handle ) {
if (!handle) {
content.classList.add(this.config.classes.handle);

@@ -345,13 +348,13 @@

const node = nodes[i];
if ( node.nodeName.toLowerCase() !== this.config.nodes.list ) {
if (node.nodeName.toLowerCase() !== this.config.nodes.list) {
content.insertBefore(node, content.firstChild);
}
}
}
} else {
for (var i = nodes.length - 1; i >= 0; i--) {
const node = nodes[i];
if ( node !== handle && node.nodeName.toLowerCase() !== this.config.nodes.list ) {
if (node !== handle && node.nodeName.toLowerCase() !== this.config.nodes.list) {
content.insertBefore(node, content.firstChild);
}
}
}
}

@@ -363,3 +366,3 @@

if ( list ) {
if (list) {
el.insertBefore(content, list);

@@ -369,7 +372,7 @@ const parent = this._makeParent(el);

if ( el.classList.contains(this.config.classes.collapsed) ) {
if (el.classList.contains(this.config.classes.collapsed)) {
this._collapseList(el);
}
for ( const i of items ) {
for (const i of items) {
this._nest(i);

@@ -379,21 +382,26 @@ }

el.appendChild(content);
}
}
}
_isDisabled(item) {
let disabled = false;
if ( item.classList.contains(this.config.classes.disabled) ) {
disabled = true;
// item has the [data-nestable-disabled] attribute
if ("nestableDisabled" in item.dataset) {
if (!item.dataset.nestableDisabled.length || item.dataset.nestableDisabled !== "false") {
return true;
}
}
if (item.classList.contains(this.config.classes.disabled)) {
return true;
}
const listEls = DOM.parents(item, `.${this.config.classes.disabled}`);
if ( listEls.length ) {
disabled = true;
if (listEls.length) {
return true;
}
return disabled;
return false;
}
/**

@@ -404,44 +412,48 @@ * Get event

_getEvent(e) {
if (this.touch) {
if (e.type === "touchend") {
return e.changedTouches[0];
}
return e.touches[0];
if (this.touch) {
if (e.type === "touchend") {
return e.changedTouches[0];
}
return e;
}
return e.touches[0];
}
return e;
}
_onMouseDown(e) {
const evt = this._getEvent(e);
const button = e.target.closest(`.${this.config.classes.button}`);
const item = e.target.closest(`.${this.config.classes.item}`);
if ( button ) {
if (button) {
return this._toggleList(item, button);
}
const handle = e.target.closest(`.${this.config.classes.handle}`);
if ( !handle ) {
if (!handle) {
return false;
}
if ( item ) {
if ( this._isDisabled(item) ) {
if (item) {
if (this._isDisabled(item)) {
return false;
}
e.preventDefault();
this.parent.classList.add(this.config.classes.moving);
item.classList.add(this.config.classes.dragging);
const rect = DOM.rect(item);
this.origin = {
x: evt.pageX, y: evt.pageY,
original: { x: evt.pageX, y: evt.pageY, }
x: evt.pageX,
y: evt.pageY,
original: {
x: evt.pageX,
y: evt.pageY,
}
};

@@ -454,100 +466,112 @@

confinedParent: false,
node: item, rect: rect,
node: item,
rect: rect,
parent: false,
axis: false,
};
if ( "nestableParent" in item.dataset ) {
// item has the [data-nestable-parent] attribute
if ("nestableParent" in item.dataset) {
const parent = document.getElementById(item.dataset.nestableParent);
if ( parent ) {
if (parent) {
this.active.parent = parent;
}
}
}
// item has the [data-nestable-axis] attribute
if ("nestableAxis" in item.dataset) {
const axis = item.dataset.nestableAxis;
if (axis === "x") {
this.active.axis = "x";
} else if (axis === "y") {
this.active.axis = "y";
}
}
this.placeholder.style.height = `${rect.height}px`;
// this.placeholder.style.width = `${rect.width}px`;
if ( this.config.showPlaceholderOnMove ) {
if (this.config.showPlaceholderOnMove) {
this.placeholder.style.opacity = 0;
}
if ( !this.container ) {
if (!this.container) {
this.container = document.createElement(this.config.nodes.list);
this.container.classList.add(this.config.classes.list);
this.container.classList.add(this.config.classes.container);
this.container.classList.add(this.config.classes.container);
this.container.id = `nestable_${this.id}`;
}
this.container.style.left = `${rect.left}px`;
this.container.style.top = `${rect.top}px`;
this.container.style.height = `${rect.height}px`;
this.container.style.width = `${rect.width}px`;
this.container.style.width = `${rect.width}px`;
item.parentNode.insertBefore(this.placeholder, item);
document.body.appendChild(this.container);
this.container.appendChild(item);
this.newParent = false;
this.dragDepth = 0;
// total depth of dragging item
const items = DOM.selectAll(this.config.nodes.item, item);
for (let i = 0; i < items.length; i++) {
const depth = DOM.parents(items[i], this.config.nodes.list).length - 1;
if (depth > this.dragDepth) {
this.dragDepth = depth;
}
const depth = DOM.parents(items[i], this.config.nodes.list).length - 1;
if (depth > this.dragDepth) {
this.dragDepth = depth;
}
}
this.emit("start", this.active);
}
}
_onMouseMove(e) {
if ( this.active ) {
if ( this.config.showPlaceholderOnMove ) {
if (this.active) {
if (this.config.showPlaceholderOnMove) {
this.placeholder.style.opacity = 1;
}
e = this._getEvent(e);
let x = e.pageX - this.origin.x;
let y = e.pageY - this.origin.y;
if ( e.pageY > this.last.y ) {
if (e.pageY > this.last.y) {
this.last.dirY = 1;
} else if ( e.pageY < this.last.y ) {
} else if (e.pageY < this.last.y) {
this.last.dirY = -1;
}
if ( e.pageX > this.last.x ) {
if (e.pageX > this.last.x) {
this.last.dirX = 1;
} else if ( e.pageX < this.last.x ) {
} else if (e.pageX < this.last.x) {
this.last.dirX = -1;
}
}
let movement = false;
if ( Math.abs(x) > Math.abs(y) ) {
if (Math.abs(x) > Math.abs(y)) {
movement = "x";
} else if ( Math.abs(x) < Math.abs(y) ) {
} else if (Math.abs(x) < Math.abs(y)) {
movement = "y";
}
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
const elements = document.elementsFromPoint(e.pageX, e.pageY - scrollTop);
if ( movement === "x" ) {
if ( this.last.dirX > 0 && x > this.config.threshold ) { // moving right
if (movement === "x" && this.active.axis !== "y") {
if (this.last.dirX > 0 && x > this.config.threshold) { // moving right
const prevEl = this.placeholder.previousElementSibling;
if ( prevEl ) {
if ( prevEl.classList.contains(this.config.classes.collapsed) ) {
if ( !this.active.collapsedParent ) {
if (prevEl) {
if (prevEl.classList.contains(this.config.classes.collapsed)) {
if (!this.active.collapsedParent) {
this.emit("error.collapsed", this.active.node, prevEl);

@@ -560,12 +584,12 @@

if ( !disabled ) {
if (!disabled) {
const depth = DOM.parents(this.placeholder, this.config.nodes.list).length;
let allowNesting = depth + this.dragDepth <= this.config.maxDepth;
let parentEl = prevEl.querySelector(this.config.nodes.list);
let allowNesting = depth + this.dragDepth <= this.config.maxDepth;
let parentEl = prevEl.querySelector(this.config.nodes.list);
if ( allowNesting ) {
if (allowNesting) {
this.active.maxDepth = false;
const oldParent = this.placeholder.closest(`.${this.config.classes.list}`);
if ( !parentEl ) {
if (!parentEl) {
parentEl = this._makeParent(prevEl);

@@ -578,3 +602,3 @@ }

});
this.emit("nest", parentEl, oldParent);

@@ -584,3 +608,3 @@

} else {
if ( !this.active.maxDepth ) {
if (!this.active.maxDepth) {
this.emit("error.maxdepth", this.active.node, this.config.maxDepth);

@@ -592,3 +616,3 @@

} else {
if ( !this.active.disabledParent ) {
if (!this.active.disabledParent) {
this.emit("error.disabled");

@@ -601,5 +625,5 @@

}
} else if ( this.last.dirX < 0 && x < -this.config.threshold ) { // moving left
} else if (this.last.dirX < 0 && x < -this.config.threshold) { // moving left
this.active.maxDepth = false;

@@ -609,12 +633,12 @@ this.active.disabledParent = false;

// this.active.confinedParent = false;
const listEl = this.placeholder.closest(this.config.nodes.list);
const parentEl = listEl.closest(this.config.nodes.item);
if ( parentEl &&
((listEl.childElementCount > 1 && this.placeholder !== listEl.firstElementChild) || listEl.childElementCount < 2 && this.placeholder === listEl.firstElementChild) ) {
if (parentEl &&
((listEl.childElementCount > 1 && this.placeholder !== listEl.firstElementChild) || listEl.childElementCount < 2 && this.placeholder === listEl.firstElementChild)) {
const nextEl = parentEl.nextElementSibling;
const oldParent = this.placeholder.closest(`.${this.config.classes.list}`);
if ( nextEl ) {
if (nextEl) {
const list = nextEl.closest(this.config.nodes.list);

@@ -626,3 +650,3 @@ this._moveElement(this.placeholder, {

});
this.origin.x = e.pageX;

@@ -633,7 +657,7 @@ } else {

type: "appendChild",
});
});
this.origin.x = e.pageX;
}
this.emit("unnest", parentEl, oldParent);

@@ -644,13 +668,16 @@ }

// check if we're over a valid item
for ( const element of elements ) {
if ( element !== this.active.node &&
!this.active.node.contains(element) &&
element.classList.contains(this.config.classes.content) ) {
for (const element of elements) {
const moveY = element !== this.active.node &&
!this.active.node.contains(element) &&
element.classList.contains(this.config.classes.content) &&
this.active.axis !== "x";
if (moveY) {
const item = element.closest(`.${this.config.classes.item}`);
if ( item ) {
if ( movement === "y" ) {
if (item) {
if (movement === "y") {
const childListEl = item.querySelector(this.config.nodes.list);
if ( childListEl && !item.classList.contains(this.config.classes.collapsed) ) { // item is parent
if ( this.last.dirY > 0 ) { // moving item down
if (childListEl && !item.classList.contains(this.config.classes.collapsed)) { // item is parent
if (this.last.dirY > 0) { // moving item down
this._moveElement(this.placeholder, {

@@ -661,4 +688,4 @@ parent: item.lastElementChild,

animatable: item.querySelector(`.${this.config.classes.content}`)
});
} else if ( this.last.dirY < 0 ) { // moving item up
});
} else if (this.last.dirY < 0) { // moving item up
this._moveElement(this.placeholder, {

@@ -669,11 +696,11 @@ parent: item.parentNode,

animatable: item.querySelector(`.${this.config.classes.content}`)
});
});
}
this.emit("reorder");
} else { // item is not a parent
if ( this.last.dirY > 0 ) { // moving item down
if (this.last.dirY > 0) { // moving item down
const nextEl = item.nextElementSibling;
if ( nextEl ) { // item has an item below it
if (nextEl) { // item has an item below it
this._moveElement(this.placeholder, {

@@ -692,3 +719,3 @@ parent: item.parentNode,

}
} else if ( this.last.dirY < 0 ) { // moving item up
} else if (this.last.dirY < 0) { // moving item up
this._moveElement(this.placeholder, {

@@ -699,3 +726,3 @@ parent: item.parentNode,

animatable: item.querySelector(`.${this.config.classes.content}`)
});
});
}

@@ -707,8 +734,8 @@

}
const parentEl = item.closest(`.${this.config.classes.parent}`);
if ( parentEl ) {
if ( parentEl !== this.parent ) {
if ( parentEl._nestable ) {
if (parentEl) {
if (parentEl !== this.parent) {
if (parentEl._nestable) {
this.newParent = parentEl;

@@ -721,11 +748,23 @@ }

}
this.placeholder.classList.toggle(this.config.classes.error,
this.active.disabledParent ||
this.active.maxDepth ||
this.active.collapsedParent ||
this.active.confinedParent);
this.container.style.transform = `translate3d(${e.pageX - this.origin.original.x}px, ${e.pageY - this.origin.original.y}px, 0)`;
this.active.disabledParent ||
this.active.maxDepth ||
this.active.collapsedParent ||
this.active.confinedParent);
let mx = e.pageX - this.origin.original.x;
let my = e.pageY - this.origin.original.y;
// item movement is confined
if (this.active.axis) {
if (this.active.axis === "x") {
my = 0;
} else if (this.active.axis === "y") {
mx = 0;
}
}
this.container.style.transform = `translate3d(${mx}px, ${my}px, 0)`;
this.lastParent = this.placeholder.parentNode;

@@ -735,3 +774,3 @@

}
this.last = {

@@ -742,9 +781,9 @@ x: e.pageX,

}
_moveElement(el, type) {
let ppos = false;
let ipos = false;
let ipos = false;
// prevent moving if item has disabled parents
if ( this._isDisabled(type.parent) ) {
if (this._isDisabled(type.parent)) {
return false;

@@ -754,41 +793,41 @@ }

// prevent moving if item is confined to parent with data-nestable-parent
if ( this.active.parent ) {
if ( !DOM.parents(type.parent, `#${this.active.parent.id}`).includes(this.active.parent) ) {
if ( !this.active.confinedParent ) {
if (this.active.parent) {
if (!DOM.parents(type.parent, `#${this.active.parent.id}`).includes(this.active.parent)) {
if (!this.active.confinedParent) {
this.emit("error.confined", el, this.active.parent, type.parent);
this.active.confinedParent = true;
this.active.confinedParent = true;
}
return false;
}
}
let listEl = el.closest(this.config.nodes.list);
// if animation is enabled, we need to get the original position of the element first
if ( this.config.animation > 0 ) {
if (this.config.animation > 0) {
ppos = DOM.rect(this.placeholder);
if ( type.animatable ) {
if (type.animatable) {
ipos = DOM.rect(type.animatable)
}
}
if ( type.type === "insertBefore" ) {
type.parent.insertBefore(el, type.sibling);
} else if ( type.type === "appendChild" ) {
if (type.type === "insertBefore") {
type.parent.insertBefore(el, type.sibling);
} else if (type.type === "appendChild") {
type.parent.appendChild(el);
}
if ( !listEl.childElementCount ) {
if (!listEl.childElementCount) {
this._unmakeParent(listEl.parentNode);
}
this.emit("order.change", this.active.node, type.parent, listEl);
// animate the elements
if ( this.config.animation > 0 ) {
// animate the elements
if (this.config.animation > 0) {
this._animateElement(this.placeholder, ppos);
if ( type.animatable && ipos ) {
if (type.animatable && ipos) {
this._animateElement(type.animatable, ipos);

@@ -798,3 +837,3 @@ }

}
_animateElement(el, obj) {

@@ -829,3 +868,3 @@ // Animate an element's change in position

css.transition = "";
}, this.config.animation);
}, this.config.animation);
}

@@ -836,23 +875,23 @@

}
_onMouseUp(e) {
if ( this.active ) {
if ( this.config.showPlaceholderOnMove ) {
if (this.active) {
if (this.config.showPlaceholderOnMove) {
this.placeholder.style.opacity = 0;
}
}
e = this._getEvent(e);
const prect = DOM.rect(this.active.node);
// this.active.node.removeAttribute("style");
this.container.removeAttribute("style");
this.parent.classList.remove(this.config.classes.moving);
this.placeholder.parentNode.replaceChild(this.active.node, this.placeholder);
this._animateElement(this.active.node, prect);
this.placeholder.classList.remove(this.config.classes.error);

@@ -862,19 +901,19 @@ this.active.node.classList.remove(this.config.classes.dragging);

this.active = false;
document.body.removeChild(this.container);
this._getData();
if ( this.newParent ) {
if (this.newParent) {
this.newParent._nestable._getData();
}
this.emit("stop", this.data);
this.update();
}
}
_toggleList(item, btn) {
if ( !item.classList.contains(this.config.classes.collapsed) ) {
if (!item.classList.contains(this.config.classes.collapsed)) {
this._collapseList(item, btn);

@@ -885,5 +924,5 @@ } else {

}
_collapseList(item, btn) {
if ( !btn ) {
if (!btn) {
btn = item.querySelector(`.${this.config.classes.button}`)

@@ -895,5 +934,5 @@ }

}
_expandList(item, btn) {
if ( !btn ) {
if (!btn) {
btn = item.querySelector(`.${this.config.classes.button}`)

@@ -904,8 +943,8 @@ }

item.classList.remove(this.config.classes.collapsed);
}
}
_makeParent(el) {
let parentEl = el.querySelector(this.config.nodes.list);
if ( !parentEl ) {
if (!parentEl) {
parentEl = document.createElement(this.config.nodes.list);

@@ -917,3 +956,3 @@ parentEl.classList.add(this.config.classes.list);

}
const button = document.createElement("button");

@@ -924,24 +963,24 @@ button.classList.add(this.config.classes.button);

el.insertBefore(button, el.firstElementChild);
return parentEl;
}
_unmakeParent(el) {
const list = el.querySelector(this.config.nodes.list);
const btn = el.querySelector("button");
if ( list ) {
if (list) {
el.removeChild(list);
}
if ( btn ) {
if (btn) {
el.removeChild(btn);
}
return
return
}
_getData(type = "nodes") {
let data = [];
const step = (level) => {

@@ -953,8 +992,8 @@ const array = [];

const item = {};
if ( type === "nodes" ) {
if (type === "nodes") {
item.node = li;
} else {
item.data = Object.assign({}, li.dataset);
if (this.config.includeContent) {

@@ -966,3 +1005,3 @@ const content = li.querySelector(`.${this.config.classes.content}`);

}
}
}
}

@@ -975,17 +1014,17 @@

}
array.push(item);
});
return array;
};
data = step(this.parent);
if ( type === "nodes" ) {
if (type === "nodes") {
this.data = data;
}
return data;
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc