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

sortable-dnd

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sortable-dnd - npm Package Compare versions

Comparing version 0.0.6 to 0.0.7

418

dist/sortable.js
/*!
* sortable-dnd v0.0.6
* sortable-dnd v0.0.7
* open source under the MIT license

@@ -84,6 +84,20 @@ * https://github.com/mfuu/sortable-dnd#readme

};
var R_SPACE = /\s+/g;
var utils = {
/**
* add specified event listener
* @param {HTMLElement} el
* @param {String} event
* @param {Function} fn
*/
on: function on(el, event, fn) {
el.addEventListener(event, fn, !IE11OrLess && captureMode);
},
/**
* remove specified event listener
* @param {HTMLElement} el
* @param {String} event
* @param {Function} fn
*/
off: function off(el, event, fn) {

@@ -101,2 +115,9 @@ el.removeEventListener(event, fn, !IE11OrLess && captureMode);

},
/**
* get specified element's index in group
* @param {HTMLElement} group
* @param {HTMLElement} el
* @returns {Number} index
*/
index: function index(group, el) {

@@ -109,8 +130,45 @@ if (!el || !el.parentNode) return -1;

},
getRect: function getRect(children, index) {
if (!children.length) return {};
if (index < 0) return {};
return children[index].getBoundingClientRect();
/**
* Returns the "bounding client rect" of given element
* @param {HTMLElement} el The element whose boundingClientRect is wanted
*/
getRect: function getRect(el) {
if (!el.getBoundingClientRect && el !== window) return;
var rect = {
top: 0,
left: 0,
bottom: 0,
right: 0,
height: 0,
width: 0
};
var elRect;
if (el !== window && el.parentNode && el !== this.getWindowScrollingElement()) {
elRect = el.getBoundingClientRect();
rect.top = elRect.top;
rect.left = elRect.left;
rect.bottom = elRect.bottom;
rect.right = elRect.right;
rect.height = elRect.height;
rect.width = elRect.width;
} else {
rect.top = 0;
rect.left = 0;
rect.bottom = window.innerHeight;
rect.right = window.innerWidth;
rect.height = window.innerHeight;
rect.width = window.innerWidth;
}
return rect;
},
getElement: function getElement(group, dragging) {
/**
* get target Element in group
* @param {HTMLElement} group
* @param {HTMLElement} el
*/
getElement: function getElement(group, el) {
var result = {

@@ -125,14 +183,14 @@ index: -1,

var index = children.indexOf(dragging);
var index = children.indexOf(el);
if (index > -1) Object.assign(result, {
index: index,
el: children[index],
rect: children[index].getBoundingClientRect()
rect: this.getRect(children[index])
}); // children 中无法直接找到对应的dom时,需要向下寻找
for (var i = 0; i < children.length; i++) {
if (this.isChildOf(dragging, children[i])) Object.assign(result, {
if (this.isChildOf(el, children[i])) Object.assign(result, {
index: i,
el: children[i],
rect: children[i].getBoundingClientRect()
rect: this.getRect(children[i])
});

@@ -143,3 +201,9 @@ }

},
// 判断子元素是否包含在父元素中
/**
* Check if child element is contained in parent element
* @param {HTMLElement} child
* @param {HTMLElement} parent
* @returns {Boolean} true | false
*/
isChildOf: function isChildOf(child, parent) {

@@ -159,7 +223,51 @@ var parentNode;

},
/**
* add or remove element's class
* @param {HTMLElement} el element
* @param {String} name class name
* @param {Boolean} state true: add, false: remove
*/
toggleClass: function toggleClass(el, name, state) {
if (el && name) {
if (el.classList) {
el.classList[state ? 'add' : 'remove'](name);
} else {
var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
}
}
},
/**
* Check if a DOM element matches a given selector
* @param {HTMLElement} el
* @param {String} selector
* @returns
*/
matches: function matches(el, selector) {
if (!selector) return;
selector[0] === '>' && (selector = selector.substring(1));
if (el) {
try {
if (el.matches) {
return el.matches(selector);
} else if (el.msMatchesSelector) {
return el.msMatchesSelector(selector);
} else if (el.webkitMatchesSelector) {
return el.webkitMatchesSelector(selector);
}
} catch (error) {
return false;
}
}
return false;
},
animate: function animate(el, preRect) {
var _this = this;
var animation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 300;
var curRect = el.getBoundingClientRect();
var animation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 150;
var curRect = this.getRect(el);
var left = preRect.left - curRect.left;

@@ -216,2 +324,5 @@ var top = preRect.top - curRect.top;

};
},
_nextTick: function _nextTick(fn) {
return setTimeout(fn, 0);
}

@@ -268,2 +379,3 @@ };

var Ghost = /*#__PURE__*/function () {

@@ -344,38 +456,9 @@ function Ghost(options) {

/**
* @interface Options {
*
* group: HTMLElement,
*
* draggable?: Function, return element node selected when dragging, or null
*
* dragEnd?: Function, The callback function when the drag is completed
*
* ghostStyle?: Object,
*
* ghostClass?: String,
*
* }
*/
var Sortable = /*#__PURE__*/function () {
function Sortable(options) {
function Sortable(el, options) {
_classCallCheck(this, Sortable);
this.group = options.group; // 父级元素
this.$el = el; // 列表容器元素
this.dragging = options.dragging; // 必须为函数且必须返回一个 HTMLElement (e) => return e.target
this.dragEnd = options.dragEnd; // 拖拽完成时的回调函数,返回两个值(olddom, newdom) => {}
this.ghostStyle = options.ghostStyle; // 克隆元素包含的属性
this.ghostClass = options.ghostClass; // 克隆元素的类名
this.animation = options.animation || 300; // 动画延迟
this.isMousedown = false; // 记录鼠标按下
this.isMousemove = false; // 记录鼠标移动
this.options = options = Object.assign({}, options);
this.dragEl = null; // 拖拽元素

@@ -385,13 +468,11 @@

this.diff = new Diff(); // 记录拖拽前后差异
this.diff = null; // 记录拖拽前后差异
this.ghost = new Ghost({
ghostClass: this.ghostClass,
ghostStyle: this.ghostStyle
});
this.supportPointer = 'PointerEvent' in window && !Safari;
this.ghost = null; // 拖拽时蒙版元素
this.calcXY = {
x: 0,
y: 0
};
}; // 记录拖拽移动时坐标
utils.debounce(this.init(), 50); // 避免重复执行多次

@@ -403,7 +484,30 @@ }

value: function init() {
if (!this.group) {
console.error('Error: group is required');
if (!this.$el) {
console.error('Error: container element is required');
return;
}
var defaults = {
animation: 150,
// 动画延时
ghostClass: '',
ghostStyle: {},
chosenClass: '',
draggable: '',
// String: class, Function: (e) => return true
dragging: null,
// 必须为函数且必须返回一个 HTMLElement (e) => return e.target
dragEnd: null,
// 拖拽完成时的回调函数,返回两个值(olddom, newdom) => {}
supportPointer: 'PointerEvent' in window && !Safari,
ownerDocument: this.$el.ownerDocument
}; // Set default options
for (var name in defaults) {
!(name in this.options) && (this.options[name] = defaults[name]);
}
this.diff = new Diff();
this.ghost = new Ghost(this.options);
this._bindEventListener();

@@ -419,15 +523,59 @@ }

}, {
key: "_bindEventListener",
value: function _bindEventListener() {
this._onStart = this._onStart.bind(this);
this._onMove = this._onMove.bind(this);
this._onDrop = this._onDrop.bind(this);
var supportPointer = this.options.supportPointer;
if (supportPointer) {
utils.on(this.$el, 'pointerdown', this._onStart);
} else {
utils.on(this.$el, 'mousedown', this._onStart);
utils.on(this.$el, 'touchstart', this._onStart);
}
}
}, {
key: "_unbindEventListener",
value: function _unbindEventListener() {
utils.off(this.$el, 'pointerdown', this._onStart);
utils.off(this.$el, 'touchstart', this._onStart);
utils.off(this.$el, 'mousedown', this._onStart);
}
}, {
key: "_onStart",
value: function _onStart(e) {
if (e.button !== 0) return true;
if (e.target === this.group) return true;
value: function _onStart(evt) {
var _this$options2 = this.options,
dragging = _this$options2.dragging,
draggable = _this$options2.draggable;
var touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt;
var target = (touch || evt).target;
if (typeof draggable === 'function') {
if (!draggable(touch || evt)) return true;
} else if (draggable) {
if (!utils.matches(target, draggable)) return true;
}
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0) return; // only left button and enabled
if (target === this.$el) return true;
try {
// 获取拖拽元素
var element = this.dragging ? this.dragging(e) : e.target; // 不存在拖拽元素时不允许拖拽
if (document.selection) {
// Timeout neccessary for IE9
utils._nextTick(function () {
document.selection.empty();
});
} else {
window.getSelection().removeAllRanges();
} // 获取拖拽元素
var element = dragging && typeof dragging === 'function' ? dragging(touch || evt) : target; // 不存在拖拽元素时不允许拖拽
if (!element) return true;
if (element.animated) return;
this.dragEl = element;
} catch (e) {
} catch (err) {
//

@@ -437,5 +585,5 @@ return true;

this.isMousedown = true; // 获取当前元素在列表中的位置
window.sortableDndOnDown = true; // 获取当前元素在列表中的位置
var _utils$getElement = utils.getElement(this.group, this.dragEl),
var _utils$getElement = utils.getElement(this.$el, this.dragEl),
index = _utils$getElement.index,

@@ -449,29 +597,35 @@ el = _utils$getElement.el,

this.ghost.init(ghostEl, rect);
this.ghost.set('x', rect.left);
this.ghost.set('y', rect.top);
this.diff.old.rect = rect;
this.ghost.set('x', rect.left);
this.ghost.set('y', rect.top); // 记录拖拽移动时坐标
this.calcXY = {
x: e.clientX,
y: e.clientY
x: (touch || evt).clientX,
y: (touch || evt).clientY
};
this._onMoveEvents();
this._onMoveEvents(touch);
this._onUpEvents();
this._onUpEvents(touch);
}
}, {
key: "_onMove",
value: function _onMove(e) {
value: function _onMove(evt) {
evt.preventDefault();
var touch = evt.touches && evt.touches[0];
var e = touch || evt;
var clientX = e.clientX,
clientY = e.clientY;
var target = touch ? document.elementFromPoint(clientX, clientY) : e.target;
var chosenClass = this.options.chosenClass;
utils.toggleClass(this.dragEl, chosenClass, true);
this.ghost.move();
e.preventDefault();
if (!this.isMousedown) return;
if (e.clientX < 0 || e.clientY < 0) return;
if (!window.sortableDndOnDown) return;
if (clientX < 0 || clientY < 0) return;
document.body.style.cursor = 'grabbing';
this.isMousemove = true;
this.ghost.set('x', this.ghost.x + e.clientX - this.calcXY.x);
this.ghost.set('y', this.ghost.y + e.clientY - this.calcXY.y);
window.sortableDndOnMove = true;
this.ghost.set('x', this.ghost.x + clientX - this.calcXY.x);
this.ghost.set('y', this.ghost.y + clientY - this.calcXY.y);
this.calcXY = {
x: e.clientX,
y: e.clientY
x: clientX,
y: clientY
};

@@ -482,3 +636,3 @@ this.ghost.move();

var _utils$getElement2 = utils.getElement(this.group, e.target),
var _utils$getElement2 = utils.getElement(this.$el, target),
index = _utils$getElement2.index,

@@ -492,17 +646,16 @@ el = _utils$getElement2.el,

bottom = rect.bottom;
if (!el || index < 0) return;
if (top < 0 || top - this.ghost.rect.height / 3 < 0) return;
if (!el || index < 0 || top < 0) return;
if (e.clientX > left && e.clientX < right && e.clientY > top && e.clientY < bottom) {
if (clientX > left && clientX < right && clientY > top && clientY < bottom) {
this.dropEl = el; // 拖拽前后元素不一致时交换
if (this.dropEl !== this.dragEl) {
var dragRect = this.dragEl.getBoundingClientRect();
var dropRect = this.dropEl.getBoundingClientRect();
if (this.dropEl.animated) return;
var dragRect = utils.getRect(this.dragEl);
var dropRect = utils.getRect(this.dropEl);
if (utils.index(this.group, this.dragEl) < index) {
this.group.insertBefore(this.dragEl, this.dropEl.nextElementSibling);
if (utils.index(this.$el, this.dragEl) < index) {
this.$el.insertBefore(this.dragEl, this.dropEl.nextElementSibling);
} else {
this.group.insertBefore(this.dragEl, this.dropEl);
this.$el.insertBefore(this.dragEl, this.dropEl);
} // 设置动画

@@ -517,3 +670,3 @@

this.diff["new"].rect = this.dropEl.getBoundingClientRect();
this.diff["new"].rect = utils.getRect(this.dropEl);
}

@@ -529,12 +682,16 @@ }

document.body.style.cursor = '';
var _this$options3 = this.options,
dragEnd = _this$options3.dragEnd,
chosenClass = _this$options3.chosenClass;
utils.toggleClass(this.dragEl, chosenClass, false);
if (this.isMousedown && this.isMousemove) {
if (window.sortableDndOnDown && window.sortableDndOnMove) {
// 拖拽完成触发回调函数
if (this.dragEnd && typeof this.dragEnd === 'function') this.dragEnd(this.diff.old, this.diff["new"]);
if (dragEnd && typeof dragEnd === 'function') dragEnd(this.diff.old, this.diff["new"]);
}
this.isMousedown = false;
this.isMousemove = false;
this.diff.destroy();
this.ghost.destroy();
this._removeWindowState();
}

@@ -544,10 +701,11 @@ }, {

value: function _checkRange(e) {
var _this$group$getBoundi = this.group.getBoundingClientRect(),
top = _this$group$getBoundi.top,
left = _this$group$getBoundi.left,
right = _this$group$getBoundi.right,
bottom = _this$group$getBoundi.bottom;
var _utils$getRect = utils.getRect(this.$el),
top = _utils$getRect.top,
left = _utils$getRect.left,
right = _utils$getRect.right,
bottom = _utils$getRect.bottom;
if (e.clientX < left || e.clientX > right || e.clientY < top || e.clientY > bottom) {
document.body.style.cursor = 'not-allowed';
return;
}

@@ -558,29 +716,30 @@ }

value: function _resetState() {
this.isMousedown = false;
this.isMousemove = false;
this.dragEl = null;
this.dropEl = null;
this.ghost.destroy();
this.diff = new Diff();
this.diff.destroy();
this._removeWindowState();
}
}, {
key: "_bindEventListener",
value: function _bindEventListener() {
this._onStart = this._onStart.bind(this);
this._onMove = this._onMove.bind(this);
this._onDrop = this._onDrop.bind(this);
if (this.supportPointer) {
utils.on(this.group, 'pointerdown', this._onStart);
} else {
utils.on(this.group, 'mousedown', this._onStart);
}
key: "_removeWindowState",
value: function _removeWindowState() {
window.sortableDndOnDown = null;
window.sortableDndOnMove = null;
delete window.sortableDndOnDown;
delete window.sortableDndOnMove;
}
}, {
key: "_onMoveEvents",
value: function _onMoveEvents() {
if (this.supportPointer) {
utils.on(document, 'pointermove', this._onMove);
value: function _onMoveEvents(touch) {
var _this$options4 = this.options,
supportPointer = _this$options4.supportPointer,
ownerDocument = _this$options4.ownerDocument;
if (supportPointer) {
utils.on(ownerDocument, 'pointermove', this._onMove);
} else if (touch) {
utils.on(ownerDocument, 'touchmove', this._onMove);
} else {
utils.on(document, 'mousemove', this._onMove);
utils.on(ownerDocument, 'mousemove', this._onMove);
}

@@ -591,19 +750,15 @@ }

value: function _onUpEvents() {
if (this.supportPointer) {
utils.on(document, 'pointerup', this._onDrop);
} else {
utils.on(document, 'mouseup', this._onDrop);
}
var ownerDocument = this.options.ownerDocument;
utils.on(ownerDocument, 'pointerup', this._onDrop);
utils.on(ownerDocument, 'touchend', this._onDrop);
utils.on(ownerDocument, 'touchcancel', this._onDrop);
utils.on(ownerDocument, 'mouseup', this._onDrop);
}
}, {
key: "_unbindEventListener",
value: function _unbindEventListener() {
utils.off(this.group, 'mousedown', this._onStart);
utils.off(this.group, 'pointerdown', this._onStart);
}
}, {
key: "_offMoveEvents",
value: function _offMoveEvents() {
utils.off(document, 'mousemove', this._onMove);
utils.off(document, 'pointermove', this._onMove);
var ownerDocument = this.options.ownerDocument;
utils.off(ownerDocument, 'pointermove', this._onMove);
utils.off(ownerDocument, 'touchmove', this._onMove);
utils.off(ownerDocument, 'mousemove', this._onMove);
}

@@ -613,4 +768,7 @@ }, {

value: function _offUpEvents() {
utils.off(document, 'mouseup', this._onDrop);
utils.off(document, 'pointerup', this._onDrop);
var ownerDocument = this.options.ownerDocument;
utils.off(ownerDocument, 'mouseup', this._onDrop);
utils.off(ownerDocument, 'touchend', this._onDrop);
utils.off(ownerDocument, 'touchcancel', this._onDrop);
utils.off(ownerDocument, 'pointerup', this._onDrop);
}

@@ -617,0 +775,0 @@ }]);

@@ -1,1 +0,1 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).sortable=e()}(this,function(){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function o(t,e,n){e&&i(t.prototype,e),n&&i(t,n),Object.defineProperty(t,"prototype",{writable:!1})}function s(t){return function(t){if(Array.isArray(t))return r(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return r(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(n="Object"===n&&t.constructor?t.constructor.name:n)||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?r(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function r(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=new Array(e);n<e;n++)i[n]=t[n];return i}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var l=t(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),h=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),u={capture:!1,passive:!1},a={on:function(t,e,n){t.addEventListener(e,n,!l&&u)},off:function(t,e,n){t.removeEventListener(e,n,!l&&u)},getWindowScrollingElement:function(){var t=document.scrollingElement;return t||document.documentElement},index:function(t,e){return e&&e.parentNode?s(Array.from(t.children)).indexOf(e):-1},getRect:function(t,e){return!t.length||e<0?{}:t[e].getBoundingClientRect()},getElement:function(t,e){var n={index:-1,el:null,rect:{}},i=s(Array.from(t.children)),t=i.indexOf(e);-1<t&&Object.assign(n,{index:t,el:i[t],rect:i[t].getBoundingClientRect()});for(var o=0;o<i.length;o++)this.isChildOf(e,i[o])&&Object.assign(n,{index:o,el:i[o],rect:i[o].getBoundingClientRect()});return n},isChildOf:function(t,e){var n;if(t&&e)for(n=t.parentNode;n;){if(e===n)return!0;n=n.parentNode}return!1},animate:function(t,e){var n=this,i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:300,o=t.getBoundingClientRect(),s=e.left-o.left,e=e.top-o.top;this.css(t,"transition","none"),this.css(t,"transform","translate3d(".concat(s,"px, ").concat(e,"px, 0)")),t.offsetLeft,this.css(t,"transition","all ".concat(i,"ms")),this.css(t,"transform","translate3d(0px, 0px, 0px)"),clearTimeout(t.animated),t.animated=setTimeout(function(){n.css(t,"transition",""),n.css(t,"transform",""),t.animated=null},i)},css:function(t,e,n){var i=t&&t.style;if(i){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];i[e=e in i||-1!==e.indexOf("webkit")?e:"-webkit-"+e]=n+("string"==typeof n?"":"px")}},debounce:function(o,s){return function(){for(var t=this,e=arguments.length,n=new Array(e),i=0;i<e;i++)n[i]=arguments[i];clearTimeout(o.id),o.id=setTimeout(function(){o.call.apply(o,[t].concat(n))},s)}}},d=function(){function t(){n(this,t),this.old={node:null,rect:{}},this.new={node:null,rect:{}}}return o(t,[{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e}},{key:"destroy",value:function(){this.old={node:null,rect:{}},this.new={node:null,rect:{}}}}]),t}(),c=function(){function e(t){n(this,e),this.options=t,this.x=0,this.y=0,this.exist=!1}return o(e,[{key:"init",value:function(t,e){if(t){this.$el=t,this.rect=e;var n,t=this.options,i=t.ghostClass,t=t.ghostStyle,o=void 0===t?{}:t,t=e.width,e=e.height;for(n in this.$el.class=i,this.$el.style.width=t+"px",this.$el.style.height=e+"px",this.$el.style.transform="",this.$el.style.transition="",this.$el.style.position="fixed",this.$el.style.left=0,this.$el.style.top=0,this.$el.style.zIndex=1e5,this.$el.style.opacity=.8,this.$el.style.pointerEvents="none",o)a.css(this.$el,n,o[n])}else console.error("Ghost Element is required")}},{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e,this[t]=e}},{key:"move",value:function(){this.exist||(document.body.appendChild(this.$el),this.exist=!0),this.$el.style.transform="translate3d(".concat(this.x,"px, ").concat(this.y,"px, 0)")}},{key:"destroy",value:function(){this.$el&&this.$el.remove(),this.exist=!1}}]),e}();return function(){function e(t){n(this,e),this.group=t.group,this.dragging=t.dragging,this.dragEnd=t.dragEnd,this.ghostStyle=t.ghostStyle,this.ghostClass=t.ghostClass,this.animation=t.animation||300,this.isMousedown=!1,this.isMousemove=!1,this.dragEl=null,this.dropEl=null,this.diff=new d,this.ghost=new c({ghostClass:this.ghostClass,ghostStyle:this.ghostStyle}),this.supportPointer="PointerEvent"in window&&!h,this.calcXY={x:0,y:0},a.debounce(this.init(),50)}return o(e,[{key:"init",value:function(){this.group?this._bindEventListener():console.error("Error: group is required")}},{key:"destroy",value:function(){this._unbindEventListener(),this._resetState()}},{key:"_onStart",value:function(t){if(0!==t.button)return!0;if(t.target===this.group)return!0;try{var e=this.dragging?this.dragging(t):t.target;if(!e)return!0;if(e.animated)return;this.dragEl=e}catch(t){return!0}this.isMousedown=!0;var e=a.getElement(this.group,this.dragEl),n=e.index,i=e.el,e=e.rect;if(!i||n<0)return!0;i=this.dragEl.cloneNode(!0);this.ghost.init(i,e),this.diff.old.rect=e,this.ghost.set("x",e.left),this.ghost.set("y",e.top),this.calcXY={x:t.clientX,y:t.clientY},this._onMoveEvents(),this._onUpEvents()}},{key:"_onMove",value:function(t){if(this.ghost.move(),t.preventDefault(),this.isMousedown&&!(t.clientX<0||t.clientY<0)){document.body.style.cursor="grabbing",this.isMousemove=!0,this.ghost.set("x",this.ghost.x+t.clientX-this.calcXY.x),this.ghost.set("y",this.ghost.y+t.clientY-this.calcXY.y),this.calcXY={x:t.clientX,y:t.clientY},this.ghost.move(),this._checkRange(t);var e=a.getElement(this.group,t.target),n=e.index,i=e.el,e=e.rect,o=e.left,s=e.right,r=e.top,e=e.bottom;if(i&&!(n<0)&&!(r<0||r-this.ghost.rect.height/3<0)&&t.clientX>o&&t.clientX<s&&t.clientY>r&&t.clientY<e){if(this.dropEl=i,this.dropEl!==this.dragEl){o=this.dragEl.getBoundingClientRect(),s=this.dropEl.getBoundingClientRect();if(this.dropEl.animated)return;a.index(this.group,this.dragEl)<n?this.group.insertBefore(this.dragEl,this.dropEl.nextElementSibling):this.group.insertBefore(this.dragEl,this.dropEl),a.animate(this.dragEl,o,this.animation),a.animate(this.dropEl,s,this.animation),this.diff.old.node=this.dragEl,this.diff.new.node=this.dropEl}this.diff.new.rect=this.dropEl.getBoundingClientRect()}}}},{key:"_onDrop",value:function(){this._offMoveEvents(),this._offUpEvents(),document.body.style.cursor="",this.isMousedown&&this.isMousemove&&this.dragEnd&&"function"==typeof this.dragEnd&&this.dragEnd(this.diff.old,this.diff.new),this.isMousedown=!1,this.isMousemove=!1,this.diff.destroy(),this.ghost.destroy()}},{key:"_checkRange",value:function(t){var e=this.group.getBoundingClientRect(),n=e.top,i=e.left,o=e.right,e=e.bottom;(t.clientX<i||t.clientX>o||t.clientY<n||t.clientY>e)&&(document.body.style.cursor="not-allowed")}},{key:"_resetState",value:function(){this.isMousedown=!1,this.isMousemove=!1,this.dragEl=null,this.dropEl=null,this.ghost.destroy(),this.diff=new d}},{key:"_bindEventListener",value:function(){this._onStart=this._onStart.bind(this),this._onMove=this._onMove.bind(this),this._onDrop=this._onDrop.bind(this),this.supportPointer?a.on(this.group,"pointerdown",this._onStart):a.on(this.group,"mousedown",this._onStart)}},{key:"_onMoveEvents",value:function(){this.supportPointer?a.on(document,"pointermove",this._onMove):a.on(document,"mousemove",this._onMove)}},{key:"_onUpEvents",value:function(){this.supportPointer?a.on(document,"pointerup",this._onDrop):a.on(document,"mouseup",this._onDrop)}},{key:"_unbindEventListener",value:function(){a.off(this.group,"mousedown",this._onStart),a.off(this.group,"pointerdown",this._onStart)}},{key:"_offMoveEvents",value:function(){a.off(document,"mousemove",this._onMove),a.off(document,"pointermove",this._onMove)}},{key:"_offUpEvents",value:function(){a.off(document,"mouseup",this._onDrop),a.off(document,"pointerup",this._onDrop)}}]),e}()});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).sortable=e()}(this,function(){"use strict";function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function s(t,e,n){e&&o(t.prototype,e),n&&o(t,n),Object.defineProperty(t,"prototype",{writable:!1})}function r(t){return function(t){if(Array.isArray(t))return l(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t,e){if(t){if("string"==typeof t)return l(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(n="Object"===n&&t.constructor?t.constructor.name:n)||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?l(t,e):void 0}}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=new Array(e);n<e;n++)i[n]=t[n];return i}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var h=t(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),a=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),c={capture:!1,passive:!1},u=/\s+/g,d={on:function(t,e,n){t.addEventListener(e,n,!h&&c)},off:function(t,e,n){t.removeEventListener(e,n,!h&&c)},getWindowScrollingElement:function(){var t=document.scrollingElement;return t||document.documentElement},index:function(t,e){return e&&e.parentNode?r(Array.from(t.children)).indexOf(e):-1},getRect:function(t){var e;if(t.getBoundingClientRect||t===window)return e={top:0,left:0,bottom:0,right:0,height:0,width:0},t!==window&&t.parentNode&&t!==this.getWindowScrollingElement()?(t=t.getBoundingClientRect(),e.top=t.top,e.left=t.left,e.bottom=t.bottom,e.right=t.right,e.height=t.height,e.width=t.width):(e.top=0,e.left=0,e.bottom=window.innerHeight,e.right=window.innerWidth,e.height=window.innerHeight,e.width=window.innerWidth),e},getElement:function(t,e){var n={index:-1,el:null,rect:{}},i=r(Array.from(t.children)),t=i.indexOf(e);-1<t&&Object.assign(n,{index:t,el:i[t],rect:this.getRect(i[t])});for(var o=0;o<i.length;o++)this.isChildOf(e,i[o])&&Object.assign(n,{index:o,el:i[o],rect:this.getRect(i[o])});return n},isChildOf:function(t,e){var n;if(t&&e)for(n=t.parentNode;n;){if(e===n)return!0;n=n.parentNode}return!1},toggleClass:function(t,e,n){var i;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(i=(" "+t.className+" ").replace(u," ").replace(" "+e+" "," "),t.className=(i+(n?" "+e:"")).replace(u," ")))},matches:function(t,e){if(e){if(">"===e[0]&&(e=e.substring(1)),t)try{if(t.matches)return t.matches(e);if(t.msMatchesSelector)return t.msMatchesSelector(e);if(t.webkitMatchesSelector)return t.webkitMatchesSelector(e)}catch(t){return!1}return!1}},animate:function(t,e){var n=this,i=2<arguments.length&&void 0!==arguments[2]?arguments[2]:150,o=this.getRect(t),s=e.left-o.left,e=e.top-o.top;this.css(t,"transition","none"),this.css(t,"transform","translate3d(".concat(s,"px, ").concat(e,"px, 0)")),t.offsetLeft,this.css(t,"transition","all ".concat(i,"ms")),this.css(t,"transform","translate3d(0px, 0px, 0px)"),clearTimeout(t.animated),t.animated=setTimeout(function(){n.css(t,"transition",""),n.css(t,"transform",""),t.animated=null},i)},css:function(t,e,n){var i=t&&t.style;if(i){if(void 0===n)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(n=t.currentStyle),void 0===e?n:n[e];i[e=e in i||-1!==e.indexOf("webkit")?e:"-webkit-"+e]=n+("string"==typeof n?"":"px")}},debounce:function(o,s){return function(){for(var t=this,e=arguments.length,n=new Array(e),i=0;i<e;i++)n[i]=arguments[i];clearTimeout(o.id),o.id=setTimeout(function(){o.call.apply(o,[t].concat(n))},s)}},_nextTick:function(t){return setTimeout(t,0)}},f=function(){function t(){i(this,t),this.old={node:null,rect:{}},this.new={node:null,rect:{}}}return s(t,[{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e}},{key:"destroy",value:function(){this.old={node:null,rect:{}},this.new={node:null,rect:{}}}}]),t}(),p=function(){function e(t){i(this,e),this.options=t,this.x=0,this.y=0,this.exist=!1}return s(e,[{key:"init",value:function(t,e){if(t){this.$el=t,this.rect=e;var n,t=this.options,i=t.ghostClass,t=t.ghostStyle,o=void 0===t?{}:t,t=e.width,e=e.height;for(n in this.$el.class=i,this.$el.style.width=t+"px",this.$el.style.height=e+"px",this.$el.style.transform="",this.$el.style.transition="",this.$el.style.position="fixed",this.$el.style.left=0,this.$el.style.top=0,this.$el.style.zIndex=1e5,this.$el.style.opacity=.8,this.$el.style.pointerEvents="none",o)d.css(this.$el,n,o[n])}else console.error("Ghost Element is required")}},{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e,this[t]=e}},{key:"move",value:function(){this.exist||(document.body.appendChild(this.$el),this.exist=!0),this.$el.style.transform="translate3d(".concat(this.x,"px, ").concat(this.y,"px, 0)")}},{key:"destroy",value:function(){this.$el&&this.$el.remove(),this.exist=!1}}]),e}();return function(){function n(t,e){i(this,n),this.$el=t,this.options=e=Object.assign({},e),this.dragEl=null,this.dropEl=null,this.diff=null,this.ghost=null,this.calcXY={x:0,y:0},d.debounce(this.init(),50)}return s(n,[{key:"init",value:function(){if(this.$el){var t,e={animation:150,ghostClass:"",ghostStyle:{},chosenClass:"",draggable:"",dragging:null,dragEnd:null,supportPointer:"PointerEvent"in window&&!a,ownerDocument:this.$el.ownerDocument};for(t in e)t in this.options||(this.options[t]=e[t]);this.diff=new f,this.ghost=new p(this.options),this._bindEventListener()}else console.error("Error: container element is required")}},{key:"destroy",value:function(){this._unbindEventListener(),this._resetState()}},{key:"_bindEventListener",value:function(){this._onStart=this._onStart.bind(this),this._onMove=this._onMove.bind(this),this._onDrop=this._onDrop.bind(this),this.options.supportPointer?d.on(this.$el,"pointerdown",this._onStart):(d.on(this.$el,"mousedown",this._onStart),d.on(this.$el,"touchstart",this._onStart))}},{key:"_unbindEventListener",value:function(){d.off(this.$el,"pointerdown",this._onStart),d.off(this.$el,"touchstart",this._onStart),d.off(this.$el,"mousedown",this._onStart)}},{key:"_onStart",value:function(t){var e=this.options,n=e.dragging,e=e.draggable,i=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,o=(i||t).target;if("function"==typeof e){if(!e(i||t))return!0}else if(e&&!d.matches(o,e))return!0;if(!/mousedown|pointerdown/.test(t.type)||0===t.button){if(o===this.$el)return!0;try{document.selection?d._nextTick(function(){document.selection.empty()}):window.getSelection().removeAllRanges();var s=n&&"function"==typeof n?n(i||t):o;if(!s)return!0;if(s.animated)return;this.dragEl=s}catch(t){return!0}window.sortableDndOnDown=!0;e=d.getElement(this.$el,this.dragEl),n=e.index,o=e.el,s=e.rect;if(!o||n<0)return!0;e=this.dragEl.cloneNode(!0);this.ghost.init(e,s),this.ghost.set("x",s.left),this.ghost.set("y",s.top),this.diff.old.rect=s,this.calcXY={x:(i||t).clientX,y:(i||t).clientY},this._onMoveEvents(i),this._onUpEvents(i)}}},{key:"_onMove",value:function(t){t.preventDefault();var e=t.touches&&t.touches[0],t=e||t,n=t.clientX,i=t.clientY,e=e?document.elementFromPoint(n,i):t.target,o=this.options.chosenClass;if(d.toggleClass(this.dragEl,o,!0),this.ghost.move(),window.sortableDndOnDown&&!(n<0||i<0)){document.body.style.cursor="grabbing",window.sortableDndOnMove=!0,this.ghost.set("x",this.ghost.x+n-this.calcXY.x),this.ghost.set("y",this.ghost.y+i-this.calcXY.y),this.calcXY={x:n,y:i},this.ghost.move(),this._checkRange(t);var o=d.getElement(this.$el,e),t=o.index,e=o.el,o=o.rect,s=o.left,r=o.right,l=o.top,o=o.bottom;if(!(!e||t<0||l<0)&&s<n&&n<r&&l<i&&i<o){if(this.dropEl=e,this.dropEl!==this.dragEl){if(this.dropEl.animated)return;s=d.getRect(this.dragEl),n=d.getRect(this.dropEl);d.index(this.$el,this.dragEl)<t?this.$el.insertBefore(this.dragEl,this.dropEl.nextElementSibling):this.$el.insertBefore(this.dragEl,this.dropEl),d.animate(this.dragEl,s,this.animation),d.animate(this.dropEl,n,this.animation),this.diff.old.node=this.dragEl,this.diff.new.node=this.dropEl}this.diff.new.rect=d.getRect(this.dropEl)}}}},{key:"_onDrop",value:function(){this._offMoveEvents(),this._offUpEvents(),document.body.style.cursor="";var t=this.options,e=t.dragEnd,t=t.chosenClass;d.toggleClass(this.dragEl,t,!1),window.sortableDndOnDown&&window.sortableDndOnMove&&e&&"function"==typeof e&&e(this.diff.old,this.diff.new),this.diff.destroy(),this.ghost.destroy(),this._removeWindowState()}},{key:"_checkRange",value:function(t){var e=d.getRect(this.$el),n=e.top,i=e.left,o=e.right,e=e.bottom;(t.clientX<i||t.clientX>o||t.clientY<n||t.clientY>e)&&(document.body.style.cursor="not-allowed")}},{key:"_resetState",value:function(){this.dragEl=null,this.dropEl=null,this.ghost.destroy(),this.diff.destroy(),this._removeWindowState()}},{key:"_removeWindowState",value:function(){window.sortableDndOnDown=null,window.sortableDndOnMove=null,delete window.sortableDndOnDown,delete window.sortableDndOnMove}},{key:"_onMoveEvents",value:function(t){var e=this.options,n=e.supportPointer,e=e.ownerDocument;n?d.on(e,"pointermove",this._onMove):t?d.on(e,"touchmove",this._onMove):d.on(e,"mousemove",this._onMove)}},{key:"_onUpEvents",value:function(){var t=this.options.ownerDocument;d.on(t,"pointerup",this._onDrop),d.on(t,"touchend",this._onDrop),d.on(t,"touchcancel",this._onDrop),d.on(t,"mouseup",this._onDrop)}},{key:"_offMoveEvents",value:function(){var t=this.options.ownerDocument;d.off(t,"pointermove",this._onMove),d.off(t,"touchmove",this._onMove),d.off(t,"mousemove",this._onMove)}},{key:"_offUpEvents",value:function(){var t=this.options.ownerDocument;d.off(t,"mouseup",this._onDrop),d.off(t,"touchend",this._onDrop),d.off(t,"touchcancel",this._onDrop),d.off(t,"pointerup",this._onDrop)}}]),n}()});
{
"name": "sortable-dnd",
"version": "0.0.6",
"version": "0.0.7",
"description": "JS Library for Drag and Drop, supports Sortable and Draggable",

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

@@ -25,11 +25,16 @@ <p>

var DND = new Sortable({
group: document.getElementById('content'),
dragging: (e) => {
return e.target
},
dragEnd: (pre, cur) => {
...
var DND = new Sortable(
document.getElementById('content'),
{
draggable: (e) => {
return true
}, // or draggable: '.class'
dragging: (e) => {
return e.target
},
dragEnd: (pre, cur) => {
...
}
}
})
)
```

@@ -47,3 +52,3 @@

|-------------|--------------|--------------|--------------|
| `group` | `HTMLElement` | - | List parent element |
| `draggable` | `String | Function` | - | Specifies which items inside the element should be draggable, the function type must return a boolean |
| `dragging` | `Function` | (e) => e.target | Specifies the drag and drop element, which must return an HTMLElement |

@@ -53,2 +58,3 @@ | `dragEnd` | `Function` | (pre, cur) => {} | The callback function when the drag is completed |

| `ghostClass` | `String` | '' | The class of the mask element when dragging |
| `chosenClass` | `String` | {} | The class of the selected element when dragging |
| `animation` | `Number` | 300 | animation delay |

@@ -55,0 +61,0 @@

import utils from './utils.js'
import { Safari } from './brower.js'
import { Ghost, Diff } from './constructors.js'
/**
* @interface Options {
*
* group: HTMLElement,
*
* draggable?: Function, return element node selected when dragging, or null
*
* dragEnd?: Function, The callback function when the drag is completed
*
* ghostStyle?: Object,
*
* ghostClass?: String,
*
* }
* 拖拽前后差异初始化
*/
class Diff {
constructor() {
this.old = { node: null, rect: {} }
this.new = { node: null, rect: {} }
}
class Sortable {
get(key) {
return this[key]
}
set(key, value) {
this[key] = value
}
destroy() {
this.old = { node: null, rect: {} }
this.new = { node: null, rect: {} }
}
}
/**
* 拖拽中的元素
*/
class Ghost {
constructor(options) {
this.group = options.group // 父级元素
this.options = options
this.x = 0
this.y = 0
this.exist = false
}
this.dragging = options.dragging // 必须为函数且必须返回一个 HTMLElement (e) => return e.target
this.dragEnd = options.dragEnd // 拖拽完成时的回调函数,返回两个值(olddom, newdom) => {}
init(el, rect) {
if (!el) {
console.error('Ghost Element is required')
return
}
this.$el = el
this.rect = rect
const { ghostClass, ghostStyle = {} } = this.options
const { width, height } = rect
this.$el.class = ghostClass
this.$el.style.width = width + 'px'
this.$el.style.height = height + 'px'
this.$el.style.transform = ''
this.$el.style.transition = ''
this.$el.style.position = 'fixed'
this.$el.style.left = 0
this.$el.style.top = 0
this.$el.style.zIndex = 100000
this.$el.style.opacity = 0.8
this.$el.style.pointerEvents = 'none'
this.ghostStyle = options.ghostStyle // 克隆元素包含的属性
this.ghostClass = options.ghostClass // 克隆元素的类名
for (const key in ghostStyle) {
utils.css(this.$el, key, ghostStyle[key])
}
}
this.animation = options.animation || 300 // 动画延迟
get (key) {
return this[key]
}
this.isMousedown = false // 记录鼠标按下
this.isMousemove = false // 记录鼠标移动
set (key, value) {
this[key] = value
this[key] = value
}
this.dragEl = null // 拖拽元素
this.dropEl = null // 释放元素
this.diff = new Diff() // 记录拖拽前后差异
move() {
// 将初始化放在 move 事件中,避免与鼠标点击事件冲突
if (!this.exist) {
document.body.appendChild(this.$el)
this.exist = true
}
this.$el.style.transform = `translate3d(${this.x}px, ${this.y}px, 0)`
}
this.ghost = new Ghost({
ghostClass: this.ghostClass,
ghostStyle: this.ghostStyle
})
destroy() {
if (this.$el) this.$el.remove()
this.exist = false
}
}
this.supportPointer = ('PointerEvent' in window) && !Safari
class Sortable {
constructor(el, options) {
this.$el = el // 列表容器元素
this.options = options = Object.assign({}, options)
this.calcXY = { x: 0, y: 0 }
this.dragEl = null // 拖拽元素
this.dropEl = null // 释放元素
this.diff = null // 记录拖拽前后差异
this.ghost = null // 拖拽时蒙版元素
this.calcXY = { x: 0, y: 0 } // 记录拖拽移动时坐标

@@ -52,6 +103,28 @@ utils.debounce(this.init(), 50) // 避免重复执行多次

init() {
if (!this.group) {
console.error('Error: group is required')
if (!this.$el) {
console.error('Error: container element is required')
return
}
const defaults = {
animation: 150, // 动画延时
ghostClass: '',
ghostStyle: {},
chosenClass: '',
draggable: '', // String: class, Function: (e) => return true
dragging: null, // 必须为函数且必须返回一个 HTMLElement (e) => return e.target
dragEnd: null, // 拖拽完成时的回调函数,返回两个值(olddom, newdom) => {}
supportPointer: ('PointerEvent' in window) && !Safari,
ownerDocument: this.$el.ownerDocument,
}
// Set default options
for (const name in defaults) {
!(name in this.options) && (this.options[name] = defaults[name])
}
this.diff = new Diff()
this.ghost = new Ghost(this.options)
this._bindEventListener()

@@ -64,20 +137,60 @@ }

_onStart(e) {
if (e.button !== 0) return true
if (e.target === this.group) return true
_bindEventListener() {
this._onStart = this._onStart.bind(this)
this._onMove = this._onMove.bind(this)
this._onDrop = this._onDrop.bind(this)
const { supportPointer } = this.options
if (supportPointer) {
utils.on(this.$el, 'pointerdown', this._onStart)
} else {
utils.on(this.$el, 'mousedown', this._onStart)
utils.on(this.$el, 'touchstart', this._onStart)
}
}
_unbindEventListener() {
utils.off(this.$el, 'pointerdown', this._onStart)
utils.off(this.$el, 'touchstart', this._onStart)
utils.off(this.$el, 'mousedown', this._onStart)
}
_onStart(evt) {
const { dragging, draggable } = this.options
const touch = (evt.touches && evt.touches[0]) || (evt.pointerType && evt.pointerType === 'touch' && evt)
const target = (touch || evt).target
if (typeof draggable === 'function') {
if (!draggable(touch || evt)) return true
} else if (draggable) {
if (!utils.matches(target, draggable)) return true
}
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0) return // only left button and enabled
if (target === this.$el) return true
try {
if (document.selection) {
// Timeout neccessary for IE9
utils._nextTick(() => { document.selection.empty() })
} else {
window.getSelection().removeAllRanges()
}
// 获取拖拽元素
const element = this.dragging ? this.dragging(e) : e.target
const element = dragging && typeof dragging === 'function' ? dragging(touch || evt) : target
// 不存在拖拽元素时不允许拖拽
if (!element) return true
if (element.animated) return
this.dragEl = element
} catch(e) {
} catch (err) {
//
return true
}
this.isMousedown = true
}
window.sortableDndOnDown = true
// 获取当前元素在列表中的位置
const { index, el, rect } = utils.getElement(this.group, this.dragEl)
const { index, el, rect } = utils.getElement(this.$el, this.dragEl)

@@ -88,32 +201,34 @@ if (!el || index < 0) return true

const ghostEl = this.dragEl.cloneNode(true)
this.ghost.init(ghostEl, rect)
this.diff.old.rect = rect
this.ghost.set('x', rect.left)
this.ghost.set('y', rect.top)
// 记录拖拽移动时坐标
this.calcXY = { x: e.clientX, y: e.clientY }
this.diff.old.rect = rect
this.calcXY = { x: (touch || evt).clientX, y: (touch || evt).clientY }
this._onMoveEvents()
this._onUpEvents()
this._onMoveEvents(touch)
this._onUpEvents(touch)
}
_onMove(e) {
_onMove(evt) {
evt.preventDefault()
const touch = evt.touches && evt.touches[0]
const e = touch || evt
const { clientX, clientY } = e
const target = touch ? document.elementFromPoint(clientX, clientY) : e.target
const { chosenClass } = this.options
utils.toggleClass(this.dragEl, chosenClass, true)
this.ghost.move()
e.preventDefault()
if (!this.isMousedown) return
if (e.clientX < 0 || e.clientY < 0) return
if (!window.sortableDndOnDown) return
if (clientX < 0 || clientY < 0) return
document.body.style.cursor = 'grabbing'
this.isMousemove = true
window.sortableDndOnMove = true
this.ghost.set('x', this.ghost.x + e.clientX - this.calcXY.x)
this.ghost.set('y', this.ghost.y + e.clientY - this.calcXY.y)
this.calcXY = { x: e.clientX, y: e.clientY }
this.ghost.set('x', this.ghost.x + clientX - this.calcXY.x)
this.ghost.set('y', this.ghost.y + clientY - this.calcXY.y)
this.calcXY = { x: clientX, y: clientY }
this.ghost.move()

@@ -123,24 +238,20 @@

const { index, el, rect } = utils.getElement(this.group, e.target)
const { index, el, rect } = utils.getElement(this.$el, target)
const { left, right, top, bottom } = rect
if (!el || index < 0) return
if (!el || index < 0 || top < 0) return
if (top < 0 || top - (this.ghost.rect.height / 3) < 0) return
if (e.clientX > left && e.clientX < right && e.clientY > top && e.clientY < bottom) {
if (clientX > left && clientX < right && clientY > top && clientY < bottom) {
this.dropEl = el
// 拖拽前后元素不一致时交换
if (this.dropEl !== this.dragEl) {
if (this.dropEl.animated) return
const dragRect = this.dragEl.getBoundingClientRect()
const dropRect = this.dropEl.getBoundingClientRect()
const dragRect = utils.getRect(this.dragEl)
const dropRect = utils.getRect(this.dropEl)
if (this.dropEl.animated) return
if (utils.index(this.group, this.dragEl) < index) {
this.group.insertBefore(this.dragEl, this.dropEl.nextElementSibling)
if (utils.index(this.$el, this.dragEl) < index) {
this.$el.insertBefore(this.dragEl, this.dropEl.nextElementSibling)
} else {
this.group.insertBefore(this.dragEl, this.dropEl)
this.$el.insertBefore(this.dragEl, this.dropEl)
}

@@ -155,3 +266,3 @@

}
this.diff.new.rect = this.dropEl.getBoundingClientRect()
this.diff.new.rect = utils.getRect(this.dropEl)
}

@@ -164,18 +275,23 @@ }

document.body.style.cursor = ''
if (this.isMousedown && this.isMousemove) {
const { dragEnd, chosenClass } = this.options
utils.toggleClass(this.dragEl, chosenClass, false)
if (window.sortableDndOnDown && window.sortableDndOnMove) {
// 拖拽完成触发回调函数
if (this.dragEnd && typeof this.dragEnd === 'function')
this.dragEnd(this.diff.old, this.diff.new)
if (dragEnd && typeof dragEnd === 'function') dragEnd(this.diff.old, this.diff.new)
}
this.isMousedown = false
this.isMousemove = false
this.diff.destroy()
this.ghost.destroy()
this._removeWindowState()
}
_checkRange(e) {
const { top, left, right, bottom } = this.group.getBoundingClientRect()
const { top, left, right, bottom } = utils.getRect(this.$el)
if (e.clientX < left || e.clientX > right || e.clientY < top || e.clientY > bottom) {
document.body.style.cursor = 'not-allowed'
return
}

@@ -185,27 +301,24 @@ }

_resetState() {
this.isMousedown = false
this.isMousemove = false
this.dragEl = null
this.dropEl = null
this.ghost.destroy()
this.diff = new Diff()
this.diff.destroy()
this._removeWindowState()
}
_bindEventListener() {
this._onStart = this._onStart.bind(this)
this._onMove = this._onMove.bind(this)
this._onDrop = this._onDrop.bind(this)
if (this.supportPointer) {
utils.on(this.group, 'pointerdown', this._onStart)
} else {
utils.on(this.group, 'mousedown', this._onStart)
}
_removeWindowState() {
window.sortableDndOnDown = null
window.sortableDndOnMove = null
delete window.sortableDndOnDown
delete window.sortableDndOnMove
}
_onMoveEvents() {
if (this.supportPointer) {
utils.on(document, 'pointermove', this._onMove)
_onMoveEvents(touch) {
const { supportPointer, ownerDocument } = this.options
if (supportPointer) {
utils.on(ownerDocument, 'pointermove', this._onMove)
} else if (touch) {
utils.on(ownerDocument, 'touchmove', this._onMove)
} else {
utils.on(document, 'mousemove', this._onMove)
utils.on(ownerDocument, 'mousemove', this._onMove)
}

@@ -215,22 +328,22 @@ }

_onUpEvents() {
if (this.supportPointer) {
utils.on(document, 'pointerup', this._onDrop)
} else {
utils.on(document, 'mouseup', this._onDrop)
}
const { ownerDocument } = this.options
utils.on(ownerDocument, 'pointerup', this._onDrop)
utils.on(ownerDocument, 'touchend', this._onDrop)
utils.on(ownerDocument, 'touchcancel', this._onDrop)
utils.on(ownerDocument, 'mouseup', this._onDrop)
}
_unbindEventListener() {
utils.off(this.group, 'mousedown', this._onStart)
utils.off(this.group, 'pointerdown', this._onStart)
}
_offMoveEvents() {
utils.off(document, 'mousemove', this._onMove)
utils.off(document, 'pointermove', this._onMove)
const { ownerDocument } = this.options
utils.off(ownerDocument, 'pointermove', this._onMove)
utils.off(ownerDocument, 'touchmove', this._onMove)
utils.off(ownerDocument, 'mousemove', this._onMove)
}
_offUpEvents() {
utils.off(document, 'mouseup', this._onDrop)
utils.off(document, 'pointerup', this._onDrop)
const { ownerDocument } = this.options
utils.off(ownerDocument, 'mouseup', this._onDrop)
utils.off(ownerDocument, 'touchend', this._onDrop)
utils.off(ownerDocument, 'touchcancel', this._onDrop)
utils.off(ownerDocument, 'pointerup', this._onDrop)
}

@@ -237,0 +350,0 @@ }

@@ -8,4 +8,12 @@ import { IE11OrLess } from './brower.js'

const R_SPACE = /\s+/g
export default {
/**
* add specified event listener
* @param {HTMLElement} el
* @param {String} event
* @param {Function} fn
*/
on(el, event, fn) {

@@ -15,2 +23,8 @@ el.addEventListener(event, fn, !IE11OrLess && captureMode)

/**
* remove specified event listener
* @param {HTMLElement} el
* @param {String} event
* @param {Function} fn
*/
off(el, event, fn) {

@@ -30,2 +44,8 @@ el.removeEventListener(event, fn, !IE11OrLess && captureMode)

/**
* get specified element's index in group
* @param {HTMLElement} group
* @param {HTMLElement} el
* @returns {Number} index
*/
index(group, el) {

@@ -38,15 +58,51 @@ if (!el || !el.parentNode) return -1

getRect(children, index) {
if (!children.length) return {}
if (index < 0) return {}
return children[index].getBoundingClientRect()
/**
* Returns the "bounding client rect" of given element
* @param {HTMLElement} el The element whose boundingClientRect is wanted
*/
getRect(el) {
if (!el.getBoundingClientRect && el !== window) return
const rect = {
top: 0,
left: 0,
bottom: 0,
right: 0,
height: 0,
width: 0,
}
let elRect
if (el !== window && el.parentNode && el !== this.getWindowScrollingElement()) {
elRect = el.getBoundingClientRect()
rect.top = elRect.top
rect.left = elRect.left
rect.bottom = elRect.bottom
rect.right = elRect.right
rect.height = elRect.height
rect.width = elRect.width
} else {
rect.top = 0
rect.left = 0
rect.bottom = window.innerHeight
rect.right = window.innerWidth
rect.height = window.innerHeight
rect.width = window.innerWidth
}
return rect
},
getElement(group, dragging) {
/**
* get target Element in group
* @param {HTMLElement} group
* @param {HTMLElement} el
*/
getElement(group, el) {
const result = { index: -1, el: null, rect: {} }
const children = [...Array.from(group.children)]
// 如果能直接在子元素中找到,返回对应的index
const index = children.indexOf(dragging)
const index = children.indexOf(el)
if (index > -1)

@@ -56,3 +112,3 @@ Object.assign(result, {

el: children[index],
rect: children[index].getBoundingClientRect()
rect: this.getRect(children[index])
})

@@ -62,7 +118,7 @@

for (let i = 0; i < children.length; i++) {
if (this.isChildOf(dragging, children[i]))
if (this.isChildOf(el, children[i]))
Object.assign(result, {
index: i,
el: children[i],
rect: children[i].getBoundingClientRect()
rect: this.getRect(children[i])
})

@@ -74,3 +130,8 @@ }

// 判断子元素是否包含在父元素中
/**
* Check if child element is contained in parent element
* @param {HTMLElement} child
* @param {HTMLElement} parent
* @returns {Boolean} true | false
*/
isChildOf(child, parent) {

@@ -88,5 +149,50 @@ let parentNode

animate(el, preRect, animation = 300) {
const curRect = el.getBoundingClientRect()
/**
* add or remove element's class
* @param {HTMLElement} el element
* @param {String} name class name
* @param {Boolean} state true: add, false: remove
*/
toggleClass(el, name, state) {
if (el && name) {
if (el.classList) {
el.classList[state ? 'add' : 'remove'](name)
} else {
const className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ')
el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ')
}
}
},
/**
* Check if a DOM element matches a given selector
* @param {HTMLElement} el
* @param {String} selector
* @returns
*/
matches(el, selector) {
if (!selector) return
selector[0] === '>' && (selector = selector.substring(1))
if (el) {
try {
if (el.matches) {
return el.matches(selector)
} else if (el.msMatchesSelector) {
return el.msMatchesSelector(selector)
} else if (el.webkitMatchesSelector) {
return el.webkitMatchesSelector(selector)
}
} catch(error) {
return false
}
}
return false
},
animate(el, preRect, animation = 150) {
const curRect = this.getRect(el)
const left = preRect.left - curRect.left

@@ -136,4 +242,8 @@ const top = preRect.top - curRect.top

}
},
_nextTick(fn) {
return setTimeout(fn, 0)
}
}
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