nestablejs
Advanced tools
Comparing version 0.0.6 to 0.0.7
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> |
{ | ||
"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", |
689
src/index.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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6308322
163
8713