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

list-dragon

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

list-dragon - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

list-dragon.js

925

index.js
// list-dragon node module
// https://github.com/openfin/list-dragon
/* eslint-env node, browser */
'use strict';
/* eslint-env node, browser */
var format = require('templex');
(function (module) { // eslint-disable-line no-unused-expressions
var REVERT_TO_STYLESHEET_VALUE = null; // null removes the style
// This closure supports NodeJS-less client side includes with <script> tags. See notes at bottom of this file.
var body, transform, timer, scrollVelocity;
var format = window.templex || require('templex');
/* inject:css */
(function(){var a="div.dragon-list{position:relative;background-color:#fff}div.dragon-list>div,div.dragon-list>ul{position:absolute;left:0;right:0}div.dragon-list>div{text-align:center;background-color:#00796b;color:#fff;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);overflow:hidden;white-space:nowrap}div.dragon-list>ul{overflow-y:auto;bottom:0;margin:0;padding:0;box-shadow:0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24)}div.dragon-list>ul>li,li.dragon-pop{white-space:nowrap;list-style-type:none;border:0 solid #f4f4f4;border-bottom:1px solid #e0e0e0;cursor:move;transition:border-top-width .2s}div.dragon-list>ul>li:last-child{height:0;border-bottom:none}li.dragon-pop{position:fixed;background-color:#fff;border:1px solid #e0e0e0;left:0;top:0;overflow-x:hidden;box-shadow:rgba(0,0,0,.188235) 0 10px 20px,rgba(0,0,0,.227451) 0 6px 6px}",b=document.createElement("style"),head=document.head||document.getElementsByTagName("head")[0];b.type="text/css";if(b.styleSheet)b.styleSheet.cssText=a;else b.appendChild(document.createTextNode(a));head.insertBefore(b,head.firstChild)})();
/* endinject */
var REVERT_TO_STYLESHEET_VALUE = null; // null removes the style
/**
* @constructor ListDragon
*
* @desc This object services a set of item lists that allow dragging and dropping items within and between lists in a set.
*
* Two strategies are supported:
*
* 1. Supply your own HTML markup and let the API build the item models for you.
* To use this strategy, script your HTML and provide one of these:
* * an array of all the list item (`<li>`) tags
* * a CSS selector that points to all the list item tags
* 2. Supply your own item models and let the API build the HTML markup for you.
* To use this strategy, provide an array of model lists.
*
* The new ListDragon object's `modelLists` property references the array of model lists the API constructed for you in strategy #1 or the array of model lists you supplied for strategy #2.
*
* After the user performs a successful drag-and-drop operation, the position of the model references within the `modelLists` array is rearranged. (The models themselves are the original objects as supplied in the model lists; they are not rebuilt or altered in any way. Just the references to them are moved around.)
*
* @param {string|Element[]|modelListType[]} selectorOrModelLists - You must supply one of the items in **bold** below:
*
* 1. _For strategy #1 above (API creates models from supplied elements):_ All the list item (`<li>`) DOM elements of all the lists you want the new object to manage, as either:
* 1. **A CSS selector;** _or_
* 2. **An array of DOM elements**
* 2. _For strategy #2 above (API creates elements from supplied models):_ **An array of model lists,** each of which is in one of the following forms:
* 1. An array of item models (with various option properties hanging off of it); _and/or_
* 2. A {@link modelListType} object with those same various option properties including the required `models` property containing that same array of item models.
*
* In either case (2.1 or 2.2), each element of such arrays of item models may take the form of:
* * A string primitive; _or_
* * A {@link itemModelType} object with a various option properties including the required `label` property containing a string primitive.
*
* Regarding these string primitives, each is either:
* * A string to be displayed in the list item; _or_
* * A format string with other property values merged in, the result of which is to be displayed in the list item.
*
* @param {object} [options={}] - There are no formal options, but you can supply "global" template variables here, representing the "outer scope," after first searching each model and then each model list.
*/
function ListDragon(selectorOrModelLists, options) {
var body, transform, timer, scrollVelocity;
if (!(this instanceof ListDragon)) {
throw error('Not called with "new" keyword.');
}
/* inject:css */
(function(){var a="div.dragon-list{position:relative;background-color:#fff}div.dragon-list>div,div.dragon-list>ul{position:absolute;left:0;right:0}div.dragon-list>div{text-align:center;background-color:#00796b;color:#fff;box-shadow:0 3px 6px rgba(0,0,0,.16),0 3px 6px rgba(0,0,0,.23);overflow:hidden;white-space:nowrap}div.dragon-list>ul{overflow-y:auto;bottom:0;margin:0;padding:0;box-shadow:0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24)}div.dragon-list>ul>li,li.dragon-pop{white-space:nowrap;list-style-type:none;border:0 solid #f4f4f4;border-bottom:1px solid #e0e0e0;cursor:move;transition:border-top-width .2s}div.dragon-list>ul>li:last-child{height:0;border-bottom:none}li.dragon-pop{position:fixed;background-color:#fff;border:1px solid #e0e0e0;left:0;top:0;overflow-x:hidden;box-shadow:rgba(0,0,0,.188235) 0 10px 20px,rgba(0,0,0,.227451) 0 6px 6px}",b=document.createElement("style"),head=document.head||document.getElementsByTagName("head")[0];b.type="text/css";if(b.styleSheet)b.styleSheet.cssText=a;else b.appendChild(document.createTextNode(a));head.insertBefore(b,head.firstChild)})();
/* endinject */
var self = this, modelLists, items;
/**
* @constructor ListDragon
*
* @desc This object services a set of item lists that allow dragging and dropping items within and between lists in a set.
*
* Two strategies are supported:
*
* 1. Supply your own HTML markup and let the API build the item models for you.
* To use this strategy, script your HTML and provide one of these:
* * an array of all the list item (`<li>`) tags
* * a CSS selector that points to all the list item tags
* 2. Supply your own item models and let the API build the HTML markup for you.
* To use this strategy, provide an array of model lists.
*
* The new ListDragon object's `modelLists` property references the array of model lists the API constructed for you in strategy #1 or the array of model lists you supplied for strategy #2.
*
* After the user performs a successful drag-and-drop operation, the position of the model references within the `modelLists` array is rearranged. (The models themselves are the original objects as supplied in the model lists; they are not rebuilt or altered in any way. Just the references to them are moved around.)
*
* @param {string|Element[]|modelListType[]} selectorOrModelLists - You must supply one of the items in **bold** below:
*
* 1. _For strategy #1 above (API creates models from supplied elements):_ All the list item (`<li>`) DOM elements of all the lists you want the new object to manage, as either:
* 1. **A CSS selector;** _or_
* 2. **An array of DOM elements**
* 2. _For strategy #2 above (API creates elements from supplied models):_ **An array of model lists,** each of which is in one of the following forms:
* 1. An array of item models (with various option properties hanging off of it); _and/or_
* 2. A {@link modelListType} object with those same various option properties including the required `models` property containing that same array of item models.
*
* In either case (2.1 or 2.2), each element of such arrays of item models may take the form of:
* * A string primitive; _or_
* * A {@link itemModelType} object with a various option properties including the required `label` property containing a string primitive.
*
* Regarding these string primitives, each is either:
* * A string to be displayed in the list item; _or_
* * A format string with other property values merged in, the result of which is to be displayed in the list item.
*
* @param {object} [options={}] - There are no formal options, but you can supply "global" template variables here, representing the "outer scope," after first searching each model and then each model list.
*/
function ListDragon(selectorOrModelLists, options) {
options = options || {};
if (!(this instanceof ListDragon)) {
throw error('Not called with "new" keyword.');
}
if (typeof selectorOrModelLists === 'string') {
items = toArray(document.querySelectorAll(selectorOrModelLists));
modelLists = createModelListsFromListElements(items);
} else if (selectorOrModelLists[0] instanceof Element) {
items = toArray(selectorOrModelLists);
modelLists = createModelListsFromListElements(items);
} else {
// param is array of model lists
// build new <ul> element(s) for each list and put in `.modelLists`;
// fill `.items` array with <li> elements from these new <ul> elements
items = [];
modelLists = createListElementsFromModelLists(selectorOrModelLists, options);
modelLists.forEach(function (list) {
items = items.concat(toArray(list.element.querySelectorAll('li')));
});
}
var self = this, modelLists, items;
// grab wheel events and don't let 'em bubble
modelLists.forEach(function (modelList) {
modelList.element.addEventListener('wheel', captureEvent);
});
options = options || {};
items.forEach(function (itemElement, index) {
var item = (itemElement !== itemElement.parentElement.lastElementChild)
? self.addEvt(itemElement, 'mousedown', itemElement, true)
: { element: itemElement };
if (typeof selectorOrModelLists === 'string') {
items = toArray(document.querySelectorAll(selectorOrModelLists));
modelLists = createModelListsFromListElements(items);
} else if (selectorOrModelLists[0] instanceof Element) {
items = toArray(selectorOrModelLists);
modelLists = createModelListsFromListElements(items);
} else {
// param is array of model lists
// build new <ul> element(s) for each list and put in `.modelLists`;
// fill `.items` array with <li> elements from these new <ul> elements
items = [];
modelLists = createListElementsFromModelLists(selectorOrModelLists, options);
modelLists.forEach(function (list) {
items = items.concat(toArray(list.element.querySelectorAll('li')));
});
}
/* `item.model` not currently needed so commented out here.
* (Originally used for rebuilding modelLists for final
* reporting, modelLists are now spliced on every successful
* drag-and-drop operation so they're always up to date.)
items.forEach(function (itemElement, index) {
var item = (itemElement !== itemElement.parentElement.lastElementChild)
? self.addEvt(itemElement, 'mousedown', itemElement, true)
: { element: itemElement };
var origin = this.itemCoordinates(itemElement);
item.model = this.modelLists[origin.list].models[origin.item];
/* `item.model` not currently needed so commented out here.
* (Originally used for rebuilding modelLists for final
* reporting, modelLists are now spliced on every successful
* drag-and-drop operation so they're always up to date.)
*/
var origin = this.itemCoordinates(itemElement);
item.model = this.modelLists[origin.list].models[origin.item];
items[index] = item;
});
*/
body = body || document.getElementsByTagName('body')[0];
items[index] = item;
});
transform = 'transform' in items[0].element.style
? 'transform' // Chrome 45 and Firefox 40
: '-webkit-transform'; // Safari 8
body = body || document.getElementsByTagName('body')[0];
// set up the new object
this.modelLists = modelLists;
this.items = items;
this.bindings = {};
this.callback = {};
transform = 'transform' in items[0].element.style
? 'transform' // Chrome 45 and Firefox 40
: '-webkit-transform'; // Safari 8
}
// set up the new object
this.modelLists = modelLists;
this.items = items;
this.bindings = {};
this.callback = {};
ListDragon.prototype = {
}
addEvt: function (target, type, listener, doNotBind) {
var binding = {
handler: handlers[type].bind(target, this),
element: listener || window
};
ListDragon.prototype = {
if (!doNotBind) {
this.bindings[type] = binding;
}
addEvt: function (target, type, listener, doNotBind) {
var binding = {
handler: handlers[type].bind(target, this),
element: listener || window
};
binding.element.addEventListener(type, binding.handler);
if (!doNotBind) {
this.bindings[type] = binding;
}
return binding;
},
binding.element.addEventListener(type, binding.handler);
removeEvt: function (type) {
var binding = this.bindings[type];
delete this.bindings[type];
binding.element.removeEventListener(type, binding.handler);
},
return binding;
},
removeEvt: function (type) {
removeAllEventListeners: function () {
// remove drag & drop events (mousemove, mouseup, and transitionend)
for (var type in this.bindings) {
var binding = this.bindings[type];
delete this.bindings[type];
binding.element.removeEventListener(type, binding.handler);
},
removeAllEventListeners: function () {
// remove drag & drop events (mousemove, mouseup, and transitionend)
for (var type in this.bindings) {
var binding = this.bindings[type];
binding.element.removeEventListener(type, binding.handler);
}
// remove the mousedown events from all list items
this.items.forEach(function (item) {
if (item.handler) {
item.element.removeEventListener('mousedown', item.handler);
}
// remove the mousedown events from all list items
this.items.forEach(function (item) {
if (item.handler) {
item.element.removeEventListener('mousedown', item.handler);
}
});
},
});
// wheel events on the list elements
this.modelLists.forEach(function (modelList) {
modelList.element.removeEventListener('wheel', captureEvent);
});
},
pointInListRects: function (point) {
return this.modelLists.find(function (modelList) {
var rect = modelList.element.getBoundingClientRect();
pointInListRects: function (point) {
return this.modelLists.find(function (modelList) {
var rect = modelList.element.getBoundingClientRect();
rect = {
left: window.scrollX + rect.left,
top: window.scrollY + rect.top,
right: window.scrollX + rect.right,
bottom: window.scrollY + rect.bottom,
width: rect.width,
height: rect.height
};
rect = {
left: window.scrollX + rect.left,
top: window.scrollY + rect.top,
right: window.scrollX + rect.right,
bottom: window.scrollY + rect.bottom,
width: rect.width,
height: rect.height
};
modelList.rect = rect;
if (pointInRect(point, rect)) {
modelList.rect = rect;
return true; // found
} else {
return false;
}
});
},
if (pointInRect(point, rect)) {
modelList.rect = rect;
return true; // found
} else {
return false;
}
});
},
pointInItemRects: function (point, except1, except2) {
return this.items.find(function (item) {
var element = item.element;
return (
element !== except1 &&
element !== except2 &&
pointInRect(point, item.rect)
);
});
},
pointInItemRects: function (point, except1, except2) {
return this.items.find(function (item) {
var element = item.element;
return (
element !== except1 &&
element !== except2 &&
pointInRect(point, item.rect)
);
});
},
// get positions of all list items in page coords (normalized for window and list scrolling)
getAllItemBoundingRects: function () {
var modelLists = this.modelLists, height;
this.items.forEach(function (item) {
var itemElement = item.element,
listElement = itemElement.parentElement,
list = modelLists.find(function (list) { return list.element === listElement; });
// get positions of all list items in page coords (normalized for window and list scrolling)
getAllItemBoundingRects: function () {
var modelLists = this.modelLists, height;
this.items.forEach(function (item) {
var itemElement = item.element,
listElement = itemElement.parentElement,
list = modelLists.find(function (list) { return list.element === listElement; });
if (
// omitted: default to true
list.isDropTarget === undefined ||
if (
// omitted: default to true
list.isDropTarget === undefined ||
// function: use return value
typeof list.isDropTarget === 'function' && list.isDropTarget() ||
// function: use return value
typeof list.isDropTarget === 'function' && list.isDropTarget() ||
// otherwise: use truthiness of given value
list.isDropTarget
) {
var rect = itemElement.getBoundingClientRect(),
bottom = rect.bottom;
// otherwise: use truthiness of given value
list.isDropTarget
) {
var rect = itemElement.getBoundingClientRect(),
bottom = rect.bottom;
if (itemElement === listElement.lastElementChild) {
bottom = listElement.getBoundingClientRect().bottom;
if (bottom < rect.top) {
bottom = rect.top + (height || 50);
}
} else {
height = rect.height;
if (itemElement === listElement.lastElementChild) {
bottom = listElement.getBoundingClientRect().bottom;
if (bottom < rect.top) {
bottom = rect.top + (height || 50);
}
rect = {
left: window.scrollX + rect.left,
right: window.scrollX + rect.right,
top: window.scrollY + rect.top + listElement.scrollTop,
bottom: window.scrollY + bottom + listElement.scrollTop
};
item.rect = rect;
} else {
height = rect.height;
}
});
},
reinsert: function (target) {
var style = target.style;
style.width = style[transform] = style.transition = REVERT_TO_STYLESHEET_VALUE;
rect = {
left: window.scrollX + rect.left,
right: window.scrollX + rect.right,
top: window.scrollY + rect.top + listElement.scrollTop,
bottom: window.scrollY + bottom + listElement.scrollTop
};
target.classList.remove('dragon-pop');
item.rect = rect;
}
});
},
this.drop.style.transitionDuration = '0s';
this.drop.style.borderTopWidth = REVERT_TO_STYLESHEET_VALUE;
this.drop.parentElement.insertBefore(target, this.drop);
reinsert: function (target) {
var style = target.style;
style.width = style[transform] = style.transition = REVERT_TO_STYLESHEET_VALUE;
delete this.drop;
},
target.classList.remove('dragon-pop');
// return an object { item: <item index within list>, list: <list index within list of lists> }
itemCoordinates: function (item) {
var listElement = item.parentElement,
coords = { item: 0 };
this.drop.style.transitionDuration = '0s';
this.drop.style.borderTopWidth = REVERT_TO_STYLESHEET_VALUE;
this.drop.parentElement.insertBefore(target, this.drop);
while ((item = item.previousElementSibling)) {
++coords.item;
}
delete this.drop;
},
this.modelLists.find(function (list, index) {
coords.list = index;
return list.element === listElement; // stop when we find the one we belong to
});
// return an object { item: <item index within list>, list: <list index within list of lists> }
itemCoordinates: function (item) {
var listElement = item.parentElement,
coords = { item: 0 };
return coords;
while ((item = item.previousElementSibling)) {
++coords.item;
}
};
this.modelLists.find(function (list, index) {
coords.list = index;
return list.element === listElement; // stop when we find the one we belong to
});
var handlers = {
mousedown: function (dragon, evt) {
return coords;
}
evt.stopPropagation();
evt.preventDefault(); //prevents user selection of rendered nodes during drag
};
if (dragon.drop) {
return;
}
var handlers = {
mousedown: function (dragon, evt) {
var rect = this.getBoundingClientRect();
evt.stopPropagation();
evt.preventDefault(); //prevents user selection of rendered nodes during drag
dragon.rect = rect = {
left: Math.round(rect.left - 1),
top: Math.round(rect.top - 1),
right: Math.round(rect.right),
bottom: Math.round(rect.bottom),
width: Math.round(rect.width),
height: Math.round(rect.height)
};
if (dragon.drop) {
return;
}
dragon.pin = {
x: window.scrollX + evt.clientX,
y: window.scrollY + evt.clientY
};
var rect = this.getBoundingClientRect();
dragon.origin = dragon.itemCoordinates(this);
dragon.rect = rect = {
left: Math.round(rect.left - 1),
top: Math.round(rect.top - 1),
right: Math.round(rect.right),
bottom: Math.round(rect.bottom),
width: Math.round(rect.width),
height: Math.round(rect.height)
};
if (dragon.callback.grabbed) {
dragon.callback.grabbed.call(this, dragon);
}
dragon.pin = {
x: window.scrollX + evt.clientX,
y: window.scrollY + evt.clientY
};
dragon.getAllItemBoundingRects();
dragon.origin = dragon.itemCoordinates(this);
dragon.drop = this.nextElementSibling;
dragon.drop.style.transitionDuration = '0s';
dragon.drop.style.borderTopWidth = rect.height + 'px';
if (dragon.callback.grabbed) {
dragon.callback.grabbed.call(this, dragon);
}
this.style.width = rect.width + 'px';
this.style.transitionDuration = '0s';
this.style[transform] = translate(
rect.left - window.scrollX,
rect.top - window.scrollY
);
this.classList.add('dragon-pop');
this.style.zIndex = window.getComputedStyle(dragon.modelLists[0].container.parentElement).zIndex;
dragon.getAllItemBoundingRects();
body.appendChild(this);
dragon.drop = this.nextElementSibling;
dragon.drop.style.transitionDuration = '0s';
dragon.drop.style.borderTopWidth = rect.height + 'px';
rect.left += window.scrollX;
rect.top += window.scrollY;
rect.right += window.scrollX;
rect.bottom += window.scrollY;
this.style.width = rect.width + 'px';
this.style.transitionDuration = '0s';
this.style[transform] = translate(
rect.left - window.scrollX,
rect.top - window.scrollY
);
this.classList.add('dragon-pop');
this.style.zIndex = window.getComputedStyle(dragon.modelLists[0].container.parentElement).zIndex;
dragon.addEvt(this, 'mousemove');
dragon.addEvt(this, 'mouseup');
},
body.appendChild(this);
mousemove: function (dragon, evt) {
dragon.drop.style.transition = REVERT_TO_STYLESHEET_VALUE;
rect.left += window.scrollX;
rect.top += window.scrollY;
rect.right += window.scrollX;
rect.bottom += window.scrollY;
var hoverList = dragon.pointInListRects({ x: evt.clientX, y: evt.clientY }) || dragon.mostRecentHoverList;
dragon.addEvt(this, 'mousemove');
dragon.addEvt(this, 'mouseup');
},
if (hoverList) {
var dx = evt.clientX - dragon.pin.x,
dy = evt.clientY - dragon.pin.y;
mousemove: function (dragon, evt) {
dragon.drop.style.transition = REVERT_TO_STYLESHEET_VALUE;
dragon.mostRecentHoverList = hoverList;
var hoverList = dragon.pointInListRects({ x: evt.clientX, y: evt.clientY }) || dragon.mostRecentHoverList;
var maxScrollY = hoverList.element.scrollHeight - hoverList.rect.height,
y = evt.clientY + window.scrollY,
magnitude;
if (hoverList) {
var dx = evt.clientX - dragon.pin.x,
dy = evt.clientY - dragon.pin.y;
if (maxScrollY > 0) {
// list is scrollable (is taller than rect)
if (hoverList.element.scrollTop > 0 && (magnitude = y - (hoverList.rect.top + 5)) < 0) {
// mouse near or above top and list is not scrolled to top yet
resetAutoScrollTimer(magnitude, 0, hoverList.element);
} else if (hoverList.element.scrollTop < maxScrollY && (magnitude = y - (hoverList.rect.bottom - 1 - 5)) > 0) {
// mouse near or below bottom and list not scrolled to bottom yet
resetAutoScrollTimer(magnitude, maxScrollY, hoverList.element);
} else {
// mouse inside
resetAutoScrollTimer();
}
dragon.mostRecentHoverList = hoverList;
var maxScrollY = hoverList.element.scrollHeight - hoverList.rect.height,
y = evt.clientY + window.scrollY,
magnitude;
if (maxScrollY > 0) {
// list is scrollable (is taller than rect)
if (hoverList.element.scrollTop > 0 && (magnitude = y - (hoverList.rect.top + 5)) < 0) {
// mouse near or above top and list is not scrolled to top yet
resetAutoScrollTimer(magnitude, 0, hoverList.element);
} else if (hoverList.element.scrollTop < maxScrollY && (magnitude = y - (hoverList.rect.bottom - 1 - 5)) > 0) {
// mouse near or below bottom and list not scrolled to bottom yet
resetAutoScrollTimer(magnitude, maxScrollY, hoverList.element);
} else {
// mouse inside
resetAutoScrollTimer();
}
}
var other = dragon.pointInItemRects({
x: evt.clientX,
y: dragon.rect.bottom + window.scrollY + dy + hoverList.element.scrollTop
}, this, dragon.drop);
var other = dragon.pointInItemRects({
x: evt.clientX,
y: dragon.rect.bottom + window.scrollY + dy + hoverList.element.scrollTop
}, this, dragon.drop);
this.style[transform] = translate(
dragon.rect.left - window.scrollX + dx,
dragon.rect.top - window.scrollY + dy
);
this.style[transform] = translate(
dragon.rect.left - window.scrollX + dx,
dragon.rect.top - window.scrollY + dy
);
if (other) {
var element = other.element;
element.style.transition = REVERT_TO_STYLESHEET_VALUE;
element.style.borderTopWidth = dragon.drop.style.borderTopWidth;
dragon.drop.style.borderTopWidth = null;
dragon.drop = element;
}
if (other) {
var element = other.element;
element.style.transition = REVERT_TO_STYLESHEET_VALUE;
element.style.borderTopWidth = dragon.drop.style.borderTopWidth;
dragon.drop.style.borderTopWidth = null;
dragon.drop = element;
}
},
}
},
mouseup: function (dragon, evt) {
resetAutoScrollTimer();
dragon.removeEvt('mousemove');
dragon.removeEvt('mouseup');
mouseup: function (dragon, evt) {
resetAutoScrollTimer();
dragon.removeEvt('mousemove');
dragon.removeEvt('mouseup');
evt.stopPropagation();
evt.stopPropagation();
var newRect = this.getBoundingClientRect();
var newRect = this.getBoundingClientRect();
if (
window.scrollX + newRect.left === dragon.rect.left &&
window.scrollY + newRect.top === dragon.rect.top
) {
dragon.reinsert(this);
} else {
var dropRect = dragon.drop.getBoundingClientRect();
if (
window.scrollX + newRect.left === dragon.rect.left &&
window.scrollY + newRect.top === dragon.rect.top
) {
dragon.reinsert(this);
} else {
var dropRect = dragon.drop.getBoundingClientRect();
dragon.addEvt(this, 'transitionend', this);
this.style.transitionDuration = REVERT_TO_STYLESHEET_VALUE; //reverts to 200ms
this.style.transitionProperty = transform;
this.style[transform] = translate(
dropRect.left - window.scrollX,
dropRect.top - window.scrollY
);
}
},
dragon.addEvt(this, 'transitionend', this);
this.style.transitionDuration = REVERT_TO_STYLESHEET_VALUE; //reverts to 200ms
this.style.transitionProperty = transform;
this.style[transform] = translate(
dropRect.left - window.scrollX,
dropRect.top - window.scrollY
);
}
},
transitionend: function (dragon, evt) {
if (evt.propertyName === transform) {
dragon.removeEvt('transitionend');
dragon.reinsert(this);
transitionend: function (dragon, evt) {
if (evt.propertyName === transform) {
dragon.removeEvt('transitionend');
dragon.reinsert(this);
this.style.transitionProperty = REVERT_TO_STYLESHEET_VALUE; //reverts to border-top-width
this.style.transitionProperty = REVERT_TO_STYLESHEET_VALUE; //reverts to border-top-width
var model = dragon.modelLists[dragon.origin.list].splice(dragon.origin.item, 1)[0];
var destination = dragon.itemCoordinates(this);
dragon.modelLists[destination.list].splice(destination.item, 0, model);
var model = dragon.modelLists[dragon.origin.list].splice(dragon.origin.item, 1)[0];
var destination = dragon.itemCoordinates(this);
dragon.modelLists[destination.list].splice(destination.item, 0, model);
if (dragon.callback.dropped) {
dragon.callback.dropped.call(this, dragon);
}
if (dragon.callback.dropped) {
dragon.callback.dropped.call(this, dragon);
}
}
};
}
};
function resetAutoScrollTimer(magnitude, limit, element) {
if (!magnitude) {
function resetAutoScrollTimer(magnitude, limit, element) {
if (!magnitude) {
clearInterval(timer);
scrollVelocity = 0;
} else {
var changeDirection =
scrollVelocity < 0 && magnitude >= 0 ||
scrollVelocity === 0 && magnitude !== 0 ||
scrollVelocity > 0 && magnitude <= 0;
scrollVelocity = magnitude > 0 ? Math.min(50, magnitude) : Math.max(-50, magnitude);
if (changeDirection) {
clearInterval(timer);
scrollVelocity = 0;
} else {
var changeDirection =
scrollVelocity < 0 && magnitude >= 0 ||
scrollVelocity === 0 && magnitude !== 0 ||
scrollVelocity > 0 && magnitude <= 0;
scrollVelocity = magnitude > 0 ? Math.min(50, magnitude) : Math.max(-50, magnitude);
if (changeDirection) {
clearInterval(timer);
timer = setInterval(function (limit) {
var scrollTop = element.scrollTop + scrollVelocity;
if (scrollVelocity < 0 && scrollTop < limit || scrollVelocity > 0 && scrollTop > limit) {
element.scrollTop = limit;
clearInterval(timer);
} else {
element.scrollTop = scrollTop;
}
}, 125);
}
timer = setInterval(function (limit) {
var scrollTop = element.scrollTop + scrollVelocity;
if (scrollVelocity < 0 && scrollTop < limit || scrollVelocity > 0 && scrollTop > limit) {
element.scrollTop = limit;
clearInterval(timer);
} else {
element.scrollTop = scrollTop;
}
}, 125);
}
}
}
function toArray(arrayLikeObject) {
return Array.prototype.slice.call(arrayLikeObject);
}
function toArray(arrayLikeObject) {
return Array.prototype.slice.call(arrayLikeObject);
}
function pointInRect(point, rect) {
return rect.top <= point.y && point.y <= rect.bottom
&& rect.left <= point.x && point.x <= rect.right;
}
function pointInRect(point, rect) {
return rect.top <= point.y && point.y <= rect.bottom
&& rect.left <= point.x && point.x <= rect.right;
}
function translate(left, top) {
return 'translate('
+ Math.floor(left + window.scrollX) + 'px,'
+ Math.floor(top + window.scrollY) + 'px)';
}
function translate(left, top) {
return 'translate('
+ Math.floor(left + window.scrollX) + 'px,'
+ Math.floor(top + window.scrollY) + 'px)';
}
function htmlEncode(string) {
var textNode = document.createTextNode(string);
function htmlEncode(string) {
var textNode = document.createTextNode(string);
return document
.createElement('a')
.appendChild(textNode)
.parentNode
.innerHTML;
}
return document
.createElement('a')
.appendChild(textNode)
.parentNode
.innerHTML;
}
/**
* Creates `<ul>...</ul>` elements and inserts them into an `element` property on each model.
* @param {object} modelLists
* @returns `modelLists`
*/
function createListElementsFromModelLists(modelLists, options) {
var templateLabel = options.label || '{label}';
/**
* Creates `<ul>...</ul>` elements and inserts them into an `element` property on each model.
* @param {object} modelLists
* @returns `modelLists`
*/
function createListElementsFromModelLists(modelLists, options) {
var templateLabel = options.label || '{label}';
modelLists.forEach(function (modelList, listIndex) {
var listLabel = modelList.label || templateLabel,
listHtmlEncode = modelList.htmlEncode !== undefined && modelList.htmlEncode || options.htmlEncode,
container = document.createElement('div'),
listElement = document.createElement('ul');
modelLists.forEach(function (modelList, listIndex) {
var listLabel = modelList.label || templateLabel,
listHtmlEncode = modelList.htmlEncode !== undefined && modelList.htmlEncode || options.htmlEncode,
container = document.createElement('div'),
listElement = document.createElement('ul');
if (modelList.models) {
Object.keys(modelList).forEach(function (key) {
if (key !== 'models') {
modelList.models[key] = modelList[key];
}
});
modelLists[listIndex] = modelList = modelList.models;
} else if (modelList instanceof Array) {
modelList.models = modelList; // point to self
} else {
throw error('List [{1}] not an array of models (with or without additional properties) OR ' +
'an object (with a `models` property containing an array of models).', listIndex);
}
if (modelList.models) {
Object.keys(modelList).forEach(function (key) {
if (key !== 'models') {
modelList.models[key] = modelList[key];
}
});
modelLists[listIndex] = modelList = modelList.models;
} else if (modelList instanceof Array) {
modelList.models = modelList; // point to self
} else {
throw error('List [{1}] not an array of models (with or without additional properties) OR ' +
'an object (with a `models` property containing an array of models).', listIndex);
}
modelList.forEach(function (model) {
var modelLabel = model.label || listLabel,
modelHtmlEncode = model.htmlEncode !== undefined && model.htmlEncode || listHtmlEncode,
modelObject = typeof model === 'object' ? model : { label: model},
label = format.call([modelObject, modelList, options], modelLabel),
itemElement = document.createElement('li');
modelList.forEach(function (model) {
var modelLabel = model.label || listLabel,
modelHtmlEncode = model.htmlEncode !== undefined && model.htmlEncode || listHtmlEncode,
modelObject = typeof model === 'object' ? model : { label: model},
label = format.call([modelObject, modelList, options], modelLabel),
itemElement = document.createElement('li');
itemElement.innerHTML = modelHtmlEncode ? htmlEncode(label) : label;
itemElement.innerHTML = modelHtmlEncode ? htmlEncode(label) : label;
listElement.appendChild(itemElement);
});
// append the final "fencepost" item -- drop target at bottom of list after all items
var itemElement = document.createElement('li');
itemElement.innerHTML = '&nbsp;';
listElement.appendChild(itemElement);
});
// append header to container
if (modelList.title) {
var header = document.createElement('div');
header.innerHTML = listHtmlEncode ? htmlEncode(modelList.title) : modelList.title;
container.appendChild(header);
}
// append the final "fencepost" item -- drop target at bottom of list after all items
var itemElement = document.createElement('li');
itemElement.innerHTML = '&nbsp;';
listElement.appendChild(itemElement);
container.appendChild(listElement);
container.className = modelList.cssClassNames || options.cssClassNames || 'dragon-list';
modelList.element = listElement;
modelList.container = container;
});
// append header to container
if (modelList.title) {
var header = document.createElement('div');
header.innerHTML = listHtmlEncode ? htmlEncode(modelList.title) : modelList.title;
container.appendChild(header);
}
return modelLists;
}
container.appendChild(listElement);
container.className = modelList.cssClassNames || options.cssClassNames || 'dragon-list';
modelList.element = listElement;
modelList.container = container;
});
/**
* Create a `.modelLists` array with these <li> elements' parent <ul> elements
* @param {Element[]} listItemElements
* @returns {Array}
*/
function createModelListsFromListElements(listItemElements) {
var modelLists = [];
return modelLists;
}
listItemElements.forEach(function (itemElement) {
var listElement = itemElement.parentElement,
container = listElement.parentElement,
models = [];
if (!modelLists.find(function (list) { return list.element === listElement; })) {
toArray(listElement.querySelectorAll('li')).forEach(function (itemElement) {
if (itemElement !== listElement.lastElementChild) {
models.push(itemElement.innerHTML);
}
});
models.element = listElement;
models.container = container;
modelLists.push(models);
}
});
/**
* Create a `.modelLists` array with these <li> elements' parent <ul> elements
* @param {Element[]} listItemElements
* @returns {Array}
*/
function createModelListsFromListElements(listItemElements) {
var modelLists = [];
return modelLists;
}
listItemElements.forEach(function (itemElement) {
var listElement = itemElement.parentElement,
container = listElement.parentElement,
models = [];
if (!modelLists.find(function (list) { return list.element === listElement; })) {
toArray(listElement.querySelectorAll('li')).forEach(function (itemElement) {
if (itemElement !== listElement.lastElementChild) {
models.push(itemElement.innerHTML);
}
});
models.element = listElement;
models.container = container;
modelLists.push(models);
}
});
function error() {
return 'list-dragon: ' + format.apply(this, Array.prototype.slice.call(arguments));
}
return modelLists;
}
// this interface consists solely of the prototypal object constructor
module.exports = ListDragon;
function captureEvent(evt) {
evt.stopPropagation();
}
})(
typeof module === 'object' && module || (window.ListDragon = {}),
typeof module === 'object' && module.exports || (window.ListDragon.exports = {})
) || (
typeof module === 'object' || (window.ListDragon = window.ListDragon.exports)
);
function error() {
return 'list-dragon: ' + format.apply(this, Array.prototype.slice.call(arguments));
}
/* About the above IIFE:
* This file is a "modified node module." It functions as usual in Node.js *and* is also usable directly in the browser.
* 1. Node.js: The IIFE is superfluous but innocuous.
* 2. In the browser: The IIFE closure serves to keep internal declarations private.
* 2.a. In the browser as a global: The logic in the actual parameter expressions + the post-invocation expression
* will put your API in `window.ListDragon`.
* 2.b. In the browser as a module: If you predefine a `window.module` object, the results will be in `module.exports`.
* The bower component `mnm` makes this easy and also provides a global `require()` function for referencing your module
* from other closures. In either case, this works with both NodeJs-style export mechanisms -- a single API assignment,
* `module.exports = yourAPI` *or* a series of individual property assignments, `module.exports.property = property`.
*
* Before the IIFE runs, the actual parameter expressions are executed:
* 1. If `window` object undefined, we're in NodeJs so assume there is a `module` object with an `exports` property
* 2. If `window` object defined, we're in browser
* 2.a. If `module` object predefined, use it
* 2.b. If `module` object undefined, create a `ListDragon` object
*
* After the IIFE returns:
* Because it always returns undefined, the expression after the || will execute:
* 1. If `window` object undefined, then we're in NodeJs so we're done
* 2. If `window` object defined, then we're in browser
* 2.a. If `module` object predefined, we're done; results are in `moudule.exports`
* 2.b. If `module` object undefined, redefine`ListDragon` to be the `ListDragon.exports` object
*/
// this interface consists solely of the prototypal object constructor
module.exports = ListDragon;
{
"name": "list-dragon",
"version": "1.1.0",
"version": "1.2.0",
"main": "./index.js",

@@ -13,3 +13,3 @@ "description": "Drag and drop items between lists.",

"dependencies": {
"templex": "^1.0.0"
"templex": "^1.3.1"
},

@@ -20,2 +20,3 @@ "devDependencies": {

"gulp": "^3.9.0",
"gulp-browserify": "^0.5.1",
"gulp-eslint": "^1.0.0",

@@ -27,2 +28,4 @@ "gulp-exclude-gitignore": "^1.0.0",

"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.5.1",
"gulp-util": "^3.0.7",
"js-string-escape": "^1.0.0",

@@ -29,0 +32,0 @@ "jsdoc": "^3.3.2",

@@ -5,1 +5,24 @@ # list-dnd

Try the [demo](https://openfin.github.io/list-dragon/demo.html).
> NOTE: As of v1.2.0, list-dragon is now a simple node module. It is no longer a "modified node module" (containing its own extra closure for use directly in a browser).
### API documentation
Detailed API docs can be found [here](http://openfin.github.io/list-dragon/global.html).
### Demo
A demo can be found [here](http://openfin.github.io/list-dragon/demo.html).
### CDN versions
To use in a browser, you have two options:
1. Incorporate the node module into your own browserified project.
2. Use the browserified versions [`list-dragon.js`](http://openfin.github.io/list-dragon/list-dragon.js) or [`list-dragon.min.js`](http://openfin.github.io/list-dragon/list-dragon.min.js) available on the Github pages CDN.
### Submodules
See the note [Regarding submodules](https://github.com/openfin/rectangular#regarding-submodules)
for important information on cloning this repo or re-purposing its build template.
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