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.8 to 0.0.9

1130

dist/nestable.js

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

*
* Version: 0.0.8
* Version: 0.0.9
*
*/
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;
}
}
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 l=d[f];l.matches(b)&&c.push(l)}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.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;if(this.config.data){var d=new XMLHttpRequest;d.responseType="json";d.open("GET",this.config.data,!0);d.onload=function(){b.load(d)};d.send(null)}}};
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 h=c.querySelector("."+a.config.classes.button);e.classList.contains(a.config.classes.handle);for(var g=document.createDocumentFragment(),k=e.childNodes.length-1;0<=k;k--)g.insertBefore(e.childNodes[k],g.firstChild);c.insertBefore(g,e);c.removeChild(e);if(d)for(d.classList.remove(a.config.classes.list),c.removeChild(h),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.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.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.removeAll=function(){for(var a=this.parent.children,b=a.length-1;0<=b;b--)this.parent.removeChild(a[b])};
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){return"nestableDisabled"in a.dataset&&(!a.dataset.nestableDisabled.length||"false"!==a.dataset.nestableDisabled)||a.classList.contains(this.config.classes.disabled)||DOM.parents(a,"."+this.config.classes.disabled).length?!0:!1};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,axis:!1};"nestableParent"in d.dataset&&(b=document.getElementById(d.dataset.nestableParent))&&(this.active.parent=b);"nestableAxis"in d.dataset&&(b=d.dataset.nestableAxis,"x"===b?this.active.axis="x":"y"===b&&(this.active.axis="y"));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&&"y"!==this.active.axis)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)&&"x"!==this.active.axis&&((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);d=a.pageX-this.origin.original.x;b=a.pageY-this.origin.original.y;this.active.axis&&("x"===this.active.axis?b=0:"y"===this.active.axis&&(d=0));this.container.style.transform="translate3d("+d+"px, "+b+"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};
Nestable.prototype.load=function(a){var b=this;this.removeAll();"response"in a&&(a=a.response);var c=function(a){var d=document.createElement(b.config.nodes.item);d.textContent=a.content;if(a.children){var e=document.createElement(b.config.nodes.list);d.appendChild(e);a=$jscomp.makeIterator(a.children);for(var h=a.next();!h.done;h=a.next())e.appendChild(c(h.value))}return d};a=$jscomp.makeIterator(a);for(var d=a.next();!d.done;d=a.next())this._nest(this.parent.appendChild(c(d.value)));this.emit("loaded")};

2

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

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

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

this.initialised = true;
if ( this.config.data ) {
const req = new XMLHttpRequest();
req.responseType = 'json';
req.open('GET', this.config.data, true);
req.onload = () => {
this.load(req);
};
req.send(null);
}
}
}
load(data) {
this.removeAll();
if ( "response" in data ) {
data = data.response;
}
const nest = (item) => {
const el = document.createElement(this.config.nodes.item);
el.textContent = item.content;
if ( item.children ) {
const list = document.createElement(this.config.nodes.list);
el.appendChild(list);
for ( const child of item.children ) {
list.appendChild(nest(child));
}
}
return el;
};
for ( const item of data ) {
this._nest(this.parent.appendChild(nest(item)))
}
this.emit("loaded");
}
destroy() {

@@ -123,0 +163,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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