sortable-dnd
Advanced tools
Comparing version 0.2.7 to 0.3.0
/*! | ||
* sortable-dnd v0.2.7 | ||
* sortable-dnd v0.3.0 | ||
* open source under the MIT license | ||
@@ -13,2 +13,28 @@ * https://github.com/mfuu/sortable-dnd#readme | ||
function ownKeys(object, enumerableOnly) { | ||
var keys = Object.keys(object); | ||
if (Object.getOwnPropertySymbols) { | ||
var symbols = Object.getOwnPropertySymbols(object); | ||
enumerableOnly && (symbols = symbols.filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(object, sym).enumerable; | ||
})), keys.push.apply(keys, symbols); | ||
} | ||
return keys; | ||
} | ||
function _objectSpread2(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = null != arguments[i] ? arguments[i] : {}; | ||
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { | ||
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); | ||
}); | ||
} | ||
return target; | ||
} | ||
function _typeof(obj) { | ||
@@ -49,2 +75,17 @@ "@babel/helpers - typeof"; | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _toConsumableArray(arr) { | ||
@@ -104,2 +145,16 @@ return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); | ||
/** | ||
* check if is HTMLElement | ||
*/ | ||
function isHTMLElement(obj) { | ||
var d = document.createElement("div"); | ||
try { | ||
d.appendChild(obj.cloneNode(true)); | ||
return obj.nodeType == 1 ? true : false; | ||
} catch (e) { | ||
return obj == window || obj == document; | ||
} | ||
} | ||
/** | ||
* set transition style | ||
@@ -353,2 +408,18 @@ * @param {HTMLElement} el | ||
/** | ||
* Gets the last child in the el, ignoring ghostEl or invisible elements (clones) | ||
* @param {HTMLElement} el Parent element | ||
* @param {selector} selector Any other elements that should be ignored | ||
* @return {HTMLElement} The last child, ignoring ghostEl | ||
*/ | ||
function lastChild(el, selector) { | ||
var last = el.lastElementChild; | ||
while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) { | ||
last = last.previousElementSibling; | ||
} | ||
return last || null; | ||
} | ||
/** | ||
* add or remove element's class | ||
@@ -397,2 +468,9 @@ * @param {HTMLElement} el element | ||
} | ||
/** | ||
* Check whether the front and rear positions are consistent | ||
*/ | ||
function offsetChanged(o1, o2) { | ||
return o1.top !== o2.top || o1.left !== o2.left; | ||
} | ||
function css(el, prop, val) { | ||
@@ -448,3 +526,8 @@ var style = el && el.style; | ||
} | ||
var expando = 'Sortable' + Date.now(); | ||
/** | ||
* Sortable states | ||
*/ | ||
var State = /*#__PURE__*/_createClass(function State() { | ||
@@ -458,3 +541,3 @@ _classCallCheck(this, State); | ||
/** | ||
* 拖拽前后差异初始化 | ||
* Difference before and after dragging | ||
*/ | ||
@@ -467,2 +550,4 @@ | ||
this.from = { | ||
sortable: null, | ||
group: null, | ||
node: null, | ||
@@ -473,2 +558,4 @@ rect: {}, | ||
this.to = { | ||
sortable: null, | ||
group: null, | ||
node: null, | ||
@@ -481,15 +568,7 @@ rect: {}, | ||
_createClass(Differ, [{ | ||
key: "get", | ||
value: function get(key) { | ||
return this[key]; | ||
} | ||
}, { | ||
key: "set", | ||
value: function set(key, value) { | ||
this[key] = value; | ||
} | ||
}, { | ||
key: "destroy", | ||
value: function destroy() { | ||
this.from = { | ||
sortable: null, | ||
group: null, | ||
node: null, | ||
@@ -500,2 +579,4 @@ rect: {}, | ||
this.to = { | ||
sortable: null, | ||
group: null, | ||
node: null, | ||
@@ -511,3 +592,3 @@ rect: {}, | ||
/** | ||
* 拖拽中的元素 | ||
* Elements being dragged | ||
*/ | ||
@@ -519,3 +600,3 @@ | ||
this.$el = null; | ||
this.el = null; | ||
this.distance = { | ||
@@ -533,3 +614,4 @@ x: 0, | ||
var append = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; | ||
this.$el = el; | ||
this.el = el; | ||
if (!append) return; | ||
var _this$options = this.options, | ||
@@ -539,19 +621,20 @@ ghostClass = _this$options.ghostClass, | ||
ghostStyle = _this$options$ghostSt === void 0 ? {} : _this$options$ghostSt; | ||
toggleClass(this.$el, ghostClass, true); | ||
css(this.$el, 'box-sizing', 'border-box'); | ||
css(this.$el, 'margin', 0); | ||
css(this.$el, 'top', rect.top); | ||
css(this.$el, 'left', rect.left); | ||
css(this.$el, 'width', rect.width); | ||
css(this.$el, 'height', rect.height); | ||
css(this.$el, 'opacity', '0.8'); // css(this.$el, 'position', IOS ? 'absolute' : 'fixed') | ||
toggleClass(this.el, ghostClass, true); | ||
css(this.el, 'box-sizing', 'border-box'); | ||
css(this.el, 'margin', 0); | ||
css(this.el, 'top', rect.top); | ||
css(this.el, 'left', rect.left); | ||
css(this.el, 'width', rect.width); | ||
css(this.el, 'height', rect.height); | ||
css(this.el, 'opacity', '0.8'); // css(this.el, 'position', IOS ? 'absolute' : 'fixed') | ||
css(this.$el, 'position', 'fixed'); | ||
css(this.$el, 'zIndex', '100000'); | ||
css(this.$el, 'pointerEvents', 'none'); | ||
css(this.el, 'position', 'fixed'); | ||
css(this.el, 'zIndex', '100000'); | ||
css(this.el, 'pointerEvents', 'none'); | ||
this.setStyle(ghostStyle); | ||
setTransition(this.$el, 'none'); | ||
setTransform(this.$el, 'translate3d(0px, 0px, 0px)'); | ||
if (append) this.container.appendChild(this.$el); | ||
css(this.$el, 'transform-origin', this.distance.x / parseInt(this.$el.style.width) * 100 + '% ' + this.distance.y / parseInt(this.$el.style.height) * 100 + '%'); | ||
setTransition(this.el, 'none'); | ||
setTransform(this.el, 'translate3d(0px, 0px, 0px)'); | ||
this.container.appendChild(this.el); | ||
css(this.el, 'transform-origin', this.distance.x / parseInt(this.el.style.width) * 100 + '% ' + this.distance.y / parseInt(this.el.style.height) * 100 + '%'); | ||
css(this.el, 'transform', 'translateZ(0)'); | ||
} | ||
@@ -562,3 +645,3 @@ }, { | ||
for (var key in style) { | ||
css(this.$el, key, style[key]); | ||
css(this.el, key, style[key]); | ||
} | ||
@@ -569,3 +652,3 @@ } | ||
value: function rect() { | ||
return getRect(this.$el); | ||
return getRect(this.el); | ||
} | ||
@@ -576,7 +659,17 @@ }, { | ||
var smooth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; | ||
if (!this.$el) return; | ||
setTransition(this.$el, smooth ? "".concat(this.options.ghostAnimation, "ms") : 'none'); | ||
setTransform(this.$el, "translate3d(".concat(x, "px, ").concat(y, "px, 0)")); | ||
if (!this.el) return; | ||
setTransition(this.el, smooth ? "".concat(this.options.ghostAnimation, "ms") : 'none'); | ||
setTransform(this.el, "translate3d(".concat(x, "px, ").concat(y, "px, 0)")); | ||
} | ||
}, { | ||
key: "clear", | ||
value: function clear() { | ||
this.distance = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
this.el && this.el.remove(); | ||
this.el = null; | ||
} | ||
}, { | ||
key: "destroy", | ||
@@ -586,5 +679,5 @@ value: function destroy(rect) { | ||
if (!this.$el) return; | ||
var left = parseInt(this.$el.style.left); | ||
var top = parseInt(this.$el.style.top); | ||
if (!this.el) return; | ||
var left = parseInt(this.el.style.left); | ||
var top = parseInt(this.el.style.top); | ||
this.move(rect.left - left, rect.top - top, true); | ||
@@ -596,12 +689,2 @@ var ghostAnimation = this.options.ghostAnimation; | ||
} | ||
}, { | ||
key: "clear", | ||
value: function clear() { | ||
this.$el && this.$el.remove(); | ||
this.distance = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
this.$el = null; | ||
} | ||
}]); | ||
@@ -620,18 +703,19 @@ | ||
return { | ||
_autoScroll: throttle(function (_this) { | ||
// check if is moving now | ||
if (!(_this.state.sortableDown && _this.state.sortableMove)) return; | ||
var _this$state$sortableM = _this.state.sortableMove, | ||
clientX = _this$state$sortableM.clientX, | ||
clientY = _this$state$sortableM.clientY; | ||
_autoScroll: throttle(function (Sortable, state) { | ||
if (!Sortable.scrollEl) return; // check if is moving now | ||
if (!(state.sortableDown && state.sortableMove)) return; | ||
var _state$sortableMove = state.sortableMove, | ||
clientX = _state$sortableMove.clientX, | ||
clientY = _state$sortableMove.clientY; | ||
if (clientX === void 0 || clientY === void 0) return; | ||
if (_this.scrollEl === _this.ownerDocument) ; else { | ||
var _this$scrollEl = _this.scrollEl, | ||
scrollTop = _this$scrollEl.scrollTop, | ||
scrollLeft = _this$scrollEl.scrollLeft, | ||
scrollHeight = _this$scrollEl.scrollHeight, | ||
scrollWidth = _this$scrollEl.scrollWidth; | ||
if (Sortable.scrollEl === Sortable.ownerDocument) ; else { | ||
var _Sortable$scrollEl = Sortable.scrollEl, | ||
scrollTop = _Sortable$scrollEl.scrollTop, | ||
scrollLeft = _Sortable$scrollEl.scrollLeft, | ||
scrollHeight = _Sortable$scrollEl.scrollHeight, | ||
scrollWidth = _Sortable$scrollEl.scrollWidth; | ||
var _getRect = getRect(_this.scrollEl), | ||
var _getRect = getRect(Sortable.scrollEl), | ||
top = _getRect.top, | ||
@@ -644,5 +728,5 @@ right = _getRect.right, | ||
var _this$options = _this.options, | ||
scrollStep = _this$options.scrollStep, | ||
scrollThreshold = _this$options.scrollThreshold; // check direction | ||
var _Sortable$options = Sortable.options, | ||
scrollStep = _Sortable$options.scrollStep, | ||
scrollThreshold = _Sortable$options.scrollThreshold; // check direction | ||
@@ -698,5 +782,5 @@ var totop = scrollTop > 0 && clientY >= top && clientY <= top + scrollThreshold; | ||
requestAnimationFrame(function () { | ||
_this.scrollEl.scrollTo(position.x, position.y); | ||
Sortable.scrollEl.scrollTo(position.x, position.y); | ||
_this._autoScroll(_this); | ||
Sortable._autoScroll(Sortable, state); | ||
}); | ||
@@ -725,6 +809,6 @@ } | ||
return { | ||
captureAnimationState: function captureAnimationState() { | ||
var children = _toConsumableArray(Array.from(this.rootEl.children)); | ||
_captureAnimationState: function _captureAnimationState(dragEl, dropEl) { | ||
var children = _toConsumableArray(Array.from(this.el.children)); | ||
var _getRange = getRange(children, this.dragEl, this.dropEl), | ||
var _getRange = getRange(children, dragEl, dropEl), | ||
start = _getRange.start, | ||
@@ -742,3 +826,3 @@ end = _getRange.end; | ||
}, | ||
animateRange: function animateRange() { | ||
_rangeAnimate: function _rangeAnimate() { | ||
var _this = this; | ||
@@ -750,6 +834,6 @@ | ||
_this.animate(target, rect, _this.options.animation); | ||
_this._animate(target, rect, _this.options.animation); | ||
}); | ||
}, | ||
animate: function animate(el, preRect) { | ||
_animate: function _animate(el, preRect) { | ||
var animation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 150; | ||
@@ -761,3 +845,3 @@ var curRect = getRect(el); | ||
setTransform(el, "translate3d(".concat(left, "px, ").concat(top, "px, 0)")); | ||
el.offsetLeft; // trigger repaint | ||
el.offsetWidth; // trigger repaint | ||
@@ -776,58 +860,108 @@ setTransition(el, "".concat(animation, "ms")); | ||
function DNDEvent() { | ||
return { | ||
_bindEventListener: function _bindEventListener() { | ||
this._onDrag = this._onDrag.bind(this); | ||
this._onMove = this._onMove.bind(this); | ||
this._onDrop = this._onDrop.bind(this); | ||
var _this$options = this.options, | ||
supportPointer = _this$options.supportPointer, | ||
supportTouch = _this$options.supportTouch; | ||
var documentExists = typeof document !== 'undefined'; | ||
var supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'); | ||
var sortables = []; | ||
var rootEl, | ||
dragEl, | ||
dropEl, | ||
nextEl, | ||
ghostEl, | ||
activeGroup, | ||
move = { | ||
x: 0, | ||
y: 0 | ||
}, | ||
state = new State(), | ||
// Status record during drag and drop | ||
differ = new Differ(); // Record the difference before and after dragging | ||
if (supportPointer) { | ||
on(this.rootEl, 'pointerdown', this._onDrag); | ||
} else if (supportTouch) { | ||
on(this.rootEl, 'touchstart', this._onDrag); | ||
} else { | ||
on(this.rootEl, 'mousedown', this._onDrag); | ||
var _prepareGroup = function _prepareGroup(options) { | ||
var group = {}; | ||
var originalGroup = options.group; | ||
if (!originalGroup || _typeof(originalGroup) != 'object') { | ||
originalGroup = { | ||
name: originalGroup | ||
}; | ||
} | ||
group.name = originalGroup.name; | ||
group.pull = originalGroup.pull; | ||
group.put = originalGroup.put; | ||
options.group = group; | ||
}; | ||
/** | ||
* get nearest Sortable | ||
*/ | ||
var _nearestSortable = function _nearestSortable(evt) { | ||
_checkPosition(evt); | ||
if (dragEl) { | ||
evt = evt.touches ? evt.touches[0] : evt; | ||
var _evt = evt, | ||
clientX = _evt.clientX, | ||
clientY = _evt.clientY; | ||
var nearest = _detectNearestSortable(clientX, clientY); | ||
if (nearest) { | ||
// Create imitation event | ||
var event = {}; | ||
for (var i in evt) { | ||
event[i] = evt[i]; | ||
} | ||
}, | ||
_clearEvent: function _clearEvent() { | ||
off(this.rootEl, 'pointerdown', this._onDrag); | ||
off(this.rootEl, 'touchstart', this._onDrag); | ||
off(this.rootEl, 'mousedown', this._onDrag); | ||
}, | ||
_bindMoveEvents: function _bindMoveEvents(touch) { | ||
if (this.options.supportPointer) { | ||
on(this.ownerDocument, 'pointermove', this._onMove); | ||
} else if (touch) { | ||
on(this.ownerDocument, 'touchmove', this._onMove); | ||
} else { | ||
on(this.ownerDocument, 'mousemove', this._onMove); | ||
} | ||
}, | ||
_unbindMoveEvents: function _unbindMoveEvents() { | ||
off(this.ownerDocument, 'pointermove', this._onMove); | ||
off(this.ownerDocument, 'touchmove', this._onMove); | ||
off(this.ownerDocument, 'mousemove', this._onMove); | ||
}, | ||
_unbindDropEvents: function _unbindDropEvents() { | ||
off(this.ownerDocument, 'pointerup', this._onDrop); | ||
off(this.ownerDocument, 'pointercancel', this._onDrop); | ||
off(this.ownerDocument, 'touchend', this._onDrop); | ||
off(this.ownerDocument, 'touchcancel', this._onDrop); | ||
off(this.ownerDocument, 'mouseup', this._onDrop); | ||
}, | ||
_unbindDragEvents: function _unbindDragEvents() { | ||
if (this.nativeDraggable) { | ||
off(this.rootEl, 'dragstart', this._onDragStart); | ||
off(this.rootEl, 'dragover', this._onDragOver); | ||
off(this.rootEl, 'dragend', this._onDrop); | ||
} | ||
event.target = document.elementFromPoint(clientX, clientY); | ||
event.rootEl = nearest; | ||
event.preventDefault = void 0; | ||
event.stopPropagation = void 0; | ||
nearest[expando]._triggerEvent(event); | ||
} | ||
}; | ||
} | ||
} | ||
}; | ||
/** | ||
* Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. | ||
* @param {Number} x X position | ||
* @param {Number} y Y position | ||
* @return {HTMLElement} Element of the first found nearest Sortable | ||
*/ | ||
var documentExists = typeof document !== 'undefined'; | ||
var supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'); | ||
var _detectNearestSortable = function _detectNearestSortable(x, y) { | ||
var result; | ||
sortables.some(function (sortable) { | ||
var threshold = sortable[expando].options.emptyInsertThreshold; | ||
if (!threshold) return; | ||
var rect = getRect(sortable), | ||
insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold, | ||
insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold; | ||
if (insideHorizontally && insideVertically) { | ||
return result = sortable; | ||
} | ||
}); | ||
return result; | ||
}; | ||
var lastPosition = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
var _checkPosition = function _checkPosition(evt) { | ||
var clientX = evt.clientX, | ||
clientY = evt.clientY; | ||
var distanceX = clientX - lastPosition.x; | ||
var distanceY = clientY - lastPosition.y; | ||
lastPosition.x = clientX; | ||
lastPosition.y = clientY; | ||
if (clientX !== void 0 && Math.abs(distanceX) < 1 && clientY !== void 0 && Math.abs(distanceY) < 1) { | ||
return; | ||
} | ||
}; | ||
/** | ||
@@ -839,2 +973,3 @@ * @class Sortable | ||
function Sortable(el, options) { | ||
@@ -845,4 +980,4 @@ if (!(el && el.nodeType && el.nodeType === 1)) { | ||
this.rootEl = el; // root element | ||
el[expando] = this; | ||
this.el = el; | ||
this.scrollEl = getParentAutoScrollElement(el, true); // scroll element | ||
@@ -853,2 +988,16 @@ | ||
var defaults = { | ||
group: '', | ||
// string: 'group' or object: { name: 'group', put: true | false, pull: true | false } | ||
animation: 150, | ||
// Define the timing of the sorting animation | ||
draggable: undefined, | ||
// String: css selector, Function: (e) => return true | ||
onDrag: undefined, | ||
// The callback function triggered when dragging starts: () => {} | ||
onMove: undefined, | ||
// The callback function during drag and drop: (from, to) => {} | ||
onDrop: undefined, | ||
// The callback function when the drag is completed: (from, to, changed) => {} | ||
onChange: undefined, | ||
// The callback function when dragging an element to change its position: (from, to) => {} | ||
autoScroll: true, | ||
@@ -866,4 +1015,2 @@ // Auto scrolling when dragging to the edge of the container | ||
// Defines whether the sortable object is available or not. When it is true, the sortable object cannot drag and drop sorting and other functions. When it is false, it can be sorted, which is equivalent to a switch. | ||
animation: 150, | ||
// Define the timing of the sorting animation | ||
ghostAnimation: 0, | ||
@@ -877,14 +1024,2 @@ // Animation when the ghost element is destroyed | ||
// Chosen element style | ||
draggable: undefined, | ||
// String: css selector, Function: (e) => return true | ||
dragging: undefined, | ||
// Set the drag element, must be a function and must return an HTMLElement: (e) => return e.target | ||
onDrag: undefined, | ||
// The callback function triggered when dragging starts: () => {} | ||
onMove: undefined, | ||
// The callback function during drag and drop: (from, to) => {} | ||
onDrop: undefined, | ||
// The callback function when the drag is completed: (from, to, changed) => {} | ||
onChange: undefined, | ||
// The callback function when dragging an element to change its position: (from, to) => {} | ||
fallbackOnBody: false, | ||
@@ -896,3 +1031,4 @@ forceFallback: false, | ||
supportPointer: 'PointerEvent' in window && !Safari, | ||
supportTouch: 'ontouchstart' in window | ||
supportTouch: 'ontouchstart' in window, | ||
emptyInsertThreshold: 5 | ||
}; // Set default options | ||
@@ -904,24 +1040,38 @@ | ||
this.container = this.options.fallbackOnBody ? document.body : this.rootEl; | ||
this.container = this.options.fallbackOnBody ? document.body : el; | ||
this.nativeDraggable = this.options.forceFallback ? false : supportDraggable; | ||
this.move = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
this.state = new State(); // Status record during drag and drop | ||
this.ghost = new Ghost(this); // Mask element while dragging | ||
this.differ = new Differ(); // Record the difference before and after dragging | ||
this.dragStartTimer = null; // setTimeout timer | ||
this.ghost = new Ghost(this); // Mask element while dragging | ||
this.autoScrollTimer = null; | ||
this.dragEl = null; // Drag element | ||
_prepareGroup(options); // Bind all private methods | ||
this.dropEl = null; // Drop element | ||
this.dragStartTimer = null; // setTimeout timer | ||
for (var fn in this) { | ||
if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { | ||
this[fn] = this[fn].bind(this); | ||
} | ||
} | ||
this.autoScrollTimer = null; | ||
Object.assign(this, DNDEvent(), Animation(), AutoScroll()); | ||
var _this$options = this.options, | ||
supportPointer = _this$options.supportPointer, | ||
supportTouch = _this$options.supportTouch; | ||
this._bindEventListener(); | ||
if (supportPointer) { | ||
on(el, 'pointerdown', this._onDrag); | ||
} else if (supportTouch) { | ||
on(el, 'touchstart', this._onDrag); | ||
} else { | ||
on(el, 'mousedown', this._onDrag); | ||
} | ||
if (this.nativeDraggable) { | ||
on(el, 'dragover', this); | ||
on(el, 'dragenter', this); | ||
} | ||
sortables.push(el); | ||
Object.assign(this, Animation(), AutoScroll()); | ||
} | ||
@@ -931,2 +1081,3 @@ | ||
constructor: Sortable, | ||
// -------------------------------- public methods ---------------------------------- | ||
@@ -937,8 +1088,16 @@ /** | ||
destroy: function destroy() { | ||
this._clearState(); | ||
this.el[expando] = null; | ||
off(this.el, 'pointerdown', this._onDrag); | ||
off(this.el, 'touchstart', this._onDrag); | ||
off(this.el, 'mousedown', this._onDrag); | ||
this._clearEvent(); // Remove draggable attributes | ||
if (this.nativeDraggable) { | ||
off(this.el, 'dragover', this); | ||
off(this.el, 'dragenter', this); | ||
} | ||
this._clearState(); // Remove draggable attributes | ||
Array.prototype.forEach.call(this.rootEl.querySelectorAll('[draggable]'), function (el) { | ||
Array.prototype.forEach.call(this.el.querySelectorAll('[draggable]'), function (el) { | ||
el.removeAttribute('draggable'); | ||
@@ -965,5 +1124,5 @@ }); | ||
evt) { | ||
var _this2 = this; | ||
var _this = this; | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0 || this.options.disabled) return; // only left button and enabled | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0 || this.options.disabled || !this.options.group.pull) return; // only left button and enabled | ||
@@ -977,13 +1136,16 @@ var _getEvent = getEvent(evt), | ||
if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') return; | ||
if (target === this.rootEl) return true; | ||
if (this.options.stopPropagation) evt.stopPropagation(); | ||
var _this$options = this.options, | ||
draggable = _this$options.draggable, | ||
dragging = _this$options.dragging; | ||
if (target === this.el) return true; | ||
if (this.options.stopPropagation) evt.stopPropagation && evt.stopPropagation(); // prevent events from bubbling | ||
var draggable = this.options.draggable; | ||
if (typeof draggable === 'function') { | ||
if (!draggable(e)) return true; | ||
// Function type must return a HTMLElement if used to specifies the drag el | ||
var value = draggable(e); | ||
if (!value) return true; | ||
if (isHTMLElement(value)) dragEl = value; // set drag element | ||
} else if (typeof draggable === 'string') { | ||
// String use as 'tag' or '.class' or '#id' | ||
if (!matches(target, draggable)) return true; | ||
} else if (draggable !== undefined) { | ||
} else if (draggable) { | ||
throw new Error("draggable expected \"function\" or \"string\" but received \"".concat(_typeof(draggable), "\"")); | ||
@@ -993,23 +1155,20 @@ } // Get the dragged element | ||
if (dragging) { | ||
if (typeof dragging === 'function') this.dragEl = dragging(e);else throw new Error("dragging expected \"function\" or \"string\" but received \"".concat(_typeof(dragging), "\"")); | ||
} else { | ||
this.dragEl = getElement(this.rootEl, target, true); | ||
} // No dragging is allowed when there is no dragging element | ||
if (!dragEl) dragEl = getElement(this.el, target, true); // No dragging is allowed when there is no dragging element | ||
if (!dragEl || dragEl.animated) return true; // solve the problem that the mobile cannot be dragged | ||
if (!this.dragEl || this.dragEl.animated) return true; // solve the problem that the mobile cannot be dragged | ||
if (touch) dragEl.style['touch-action'] = 'none'; // get the position of the dragged element in the list | ||
if (touch) this.dragEl.style['touch-action'] = 'none'; // get the position of the dragged element in the list | ||
var _getElement = getElement(this.rootEl, this.dragEl), | ||
var _getElement = getElement(this.el, dragEl), | ||
rect = _getElement.rect, | ||
offset = _getElement.offset; | ||
this.move = { | ||
move = { | ||
x: e.clientX, | ||
y: e.clientY | ||
}; | ||
this.differ.from = { | ||
node: this.dragEl, | ||
differ.from = { | ||
sortable: this, | ||
group: this.el, | ||
node: dragEl, | ||
rect: rect, | ||
@@ -1022,5 +1181,8 @@ offset: offset | ||
}; | ||
this.state.sortableDown = e; // sortable state down is active | ||
// Solve the problem that `dragend` does not take effect when the `dragover` event is not triggered | ||
state.sortableDown = e; // sortable state down is active | ||
on(this.ownerDocument, 'dragover', _nearestSortable); | ||
on(this.ownerDocument, 'mousemove', _nearestSortable); | ||
on(this.ownerDocument, 'touchmove', _nearestSortable); // Solve the problem that `dragend` does not take effect when the `dragover` event is not triggered | ||
on(this.ownerDocument, 'pointerup', this._onDrop); | ||
@@ -1037,3 +1199,3 @@ on(this.ownerDocument, 'touchend', this._onDrop); | ||
this.dragStartTimer = setTimeout(function () { | ||
return _this2._onStart(e, touch); | ||
return _this._onStart(e, touch); | ||
}, delay); | ||
@@ -1047,4 +1209,14 @@ } else { | ||
e, touch) { | ||
rootEl = this.el; | ||
nextEl = dragEl.nextSibling; | ||
activeGroup = this.options.group; | ||
if (!this.nativeDraggable || touch) { | ||
this._bindMoveEvents(touch); | ||
if (this.options.supportPointer) { | ||
on(this.ownerDocument, 'pointermove', this._onMove); | ||
} else if (touch) { | ||
on(this.ownerDocument, 'touchmove', this._onMove); | ||
} else { | ||
on(this.ownerDocument, 'mousemove', this._onMove); | ||
} | ||
@@ -1055,6 +1227,5 @@ on(this.ownerDocument, 'pointercancel', this._onDrop); | ||
// allow HTML5 drag event | ||
this.dragEl.draggable = true; | ||
this._onDragStart = this._onDragStart.bind(this); | ||
this._onDragOver = this._onDragOver.bind(this); | ||
on(this.rootEl, 'dragstart', this._onDragStart); | ||
dragEl.draggable = true; | ||
on(dragEl, 'dragend', this); | ||
on(this.el, 'dragstart', this._onDragStart); | ||
} // clear selection | ||
@@ -1075,32 +1246,78 @@ | ||
}, | ||
// -------------------------------- trigger ---------------------------------- | ||
_triggerEvent: function _triggerEvent(evt) { | ||
if (activeGroup.name !== this.options.group.name) return; | ||
rootEl = evt.rootEl; | ||
if (this.nativeDraggable) { | ||
on(this.el, 'dragend', this._onDrop); | ||
this._onDragOver(evt); | ||
} else { | ||
this._onMove(evt); | ||
} | ||
}, | ||
// -------------------------------- drag event ---------------------------------- | ||
_onDragStart: function _onDragStart(evt) { | ||
// elements can only be dragged after firefox sets setData | ||
evt.dataTransfer.setData('te', evt.target.innerText); | ||
on(this.rootEl, 'dragover', this._onDragOver); | ||
on(this.rootEl, 'dragend', this._onDrop); | ||
if (evt.dataTransfer) { | ||
evt.dataTransfer.setData('draggableEffect', evt.target.innerText); | ||
evt.dataTransfer.effectAllowed = 'move'; | ||
} | ||
on(this.el, 'dragover', this._onDragOver); | ||
on(this.el, 'dragend', this._onDrop); | ||
}, | ||
_onDragOver: function _onDragOver(evt) { | ||
if (!this.state.sortableDown) return; | ||
var stopPropagation = this.options.stopPropagation; | ||
stopPropagation && evt.stopPropagation && evt.stopPropagation(); // prevent events from bubbling | ||
if (evt.dataTransfer) evt.dataTransfer.dropEffect = 'move'; | ||
if (!state.sortableDown || !dragEl) return; | ||
evt.preventDefault !== void 0 && evt.cancelable && evt.preventDefault(); // prevent scrolling | ||
this._preventEvent(evt); | ||
var clientX = evt.clientX, | ||
clientY = evt.clientY; | ||
var distanceX = clientX - this.move.x; | ||
var distanceY = clientY - this.move.y; | ||
_checkPosition(evt); // truly started | ||
if (clientX !== void 0 && Math.abs(distanceX) <= 0 && clientY !== void 0 && Math.abs(distanceY) <= 0) { | ||
return; | ||
} // truly started | ||
this._onStarted(evt, evt); // onMove callback | ||
this._onStarted(evt, evt); | ||
if (evt.target === this.rootEl) return; | ||
this._dispatchEvent('onMove', _objectSpread2(_objectSpread2({}, differ), {}, { | ||
ghostEl: ghostEl, | ||
event: evt, | ||
originalEvent: evt | ||
})); | ||
this._onChange(this, evt.target, evt, evt); | ||
if (this.options.group.put || differ.from.group === this.el) this._onChange(evt.target, evt, evt); | ||
}, | ||
// -------------------------------- real started ---------------------------------- | ||
_onStarted: function _onStarted(e, | ||
/** originalEvent */ | ||
evt) { | ||
state.sortableMove = e; // sortable state move is active | ||
if (!ghostEl) { | ||
// onDrag callback | ||
this._dispatchEvent('onDrag', { | ||
dragEl: dragEl, | ||
event: e, | ||
originalEvent: evt | ||
}); // Init in the move event to prevent conflict with the click event | ||
var rect = differ.from.rect; | ||
ghostEl = dragEl.cloneNode(true); | ||
this.ghost.init(ghostEl, rect, !this.nativeDraggable); | ||
Sortable.ghost = ghostEl; // add class for drag element | ||
toggleClass(dragEl, this.options.chosenClass, true); | ||
dragEl.style['will-change'] = 'transform'; | ||
if (this.nativeDraggable) { | ||
this._unbindDropEvents(); | ||
on(document, 'drop', this); | ||
} | ||
if (Safari) css(document.body, 'user-select', 'none'); | ||
} | ||
}, | ||
// -------------------------------- on move ---------------------------------- | ||
@@ -1110,8 +1327,9 @@ _onMove: function _onMove( | ||
evt) { | ||
var _this3 = this; | ||
var _this2 = this; | ||
if (!this.state.sortableDown) return; | ||
if (!state.sortableDown || !dragEl) return; | ||
var _getEvent2 = getEvent(evt), | ||
e = _getEvent2.e, | ||
var _getEvent2 = getEvent(evt); | ||
_getEvent2.touch; | ||
var e = _getEvent2.e, | ||
target = _getEvent2.target; | ||
@@ -1121,4 +1339,4 @@ | ||
clientY = e.clientY; | ||
var distanceX = clientX - this.move.x; | ||
var distanceY = clientY - this.move.y; | ||
var distanceX = clientX - move.x; | ||
var distanceY = clientY - move.y; | ||
@@ -1129,7 +1347,4 @@ if (clientX !== void 0 && Math.abs(distanceX) <= 0 && clientY !== void 0 && Math.abs(distanceY) <= 0) { | ||
var stopPropagation = this.options.stopPropagation; | ||
stopPropagation && evt.stopPropagation && evt.stopPropagation(); // prevent events from bubbling | ||
this._preventEvent(evt); | ||
evt.preventDefault !== void 0 && evt.cancelable && evt.preventDefault(); // prevent scrolling | ||
this._onStarted(e, evt); | ||
@@ -1139,86 +1354,92 @@ | ||
var onMove = this.options.onMove; | ||
if (onMove && typeof onMove === 'function') onMove(this.differ.from, this.ghost.$el, e, evt); // boundary value judgment | ||
this._dispatchEvent('onMove', _objectSpread2(_objectSpread2({}, differ), {}, { | ||
ghostEl: ghostEl, | ||
event: e, | ||
originalEvent: evt | ||
})); // check if element will exchange | ||
if (clientX < 0 || clientY < 0) return; | ||
var _getRect = getRect(this.rootEl), | ||
top = _getRect.top, | ||
right = _getRect.right, | ||
bottom = _getRect.bottom, | ||
left = _getRect.left; | ||
this._onChange(target, e, evt); // auto scroll | ||
if (clientX < left || clientX > right || clientY < top || clientY > bottom) return; // check if element will exchange | ||
this._onChange(this, target, e, evt); // auto scroll | ||
clearTimeout(this.autoScrollTimer); | ||
this.autoScrollTimer && clearTimeout(this.autoScrollTimer); | ||
if (this.options.autoScroll) { | ||
this.autoScrollTimer = setTimeout(function () { | ||
return _this3._autoScroll(_this3); | ||
return _this2._autoScroll(_this2, state); | ||
}, 0); | ||
} | ||
}, | ||
_onStarted: function _onStarted(e, | ||
/** originalEvent */ | ||
evt) { | ||
this.state.sortableMove = e; // sortable state move is active | ||
// -------------------------------- on change ---------------------------------- | ||
_onChange: debounce(function (target, e, evt) { | ||
if (!lastChild(this.el)) { | ||
this.el.appendChild(dragEl); | ||
differ.to = { | ||
sortable: this, | ||
group: this.el, | ||
node: dragEl, | ||
rect: getRect(dragEl), | ||
offset: getOffset(dragEl) | ||
}; // onChange callback | ||
if (!this.ghost.$el) { | ||
// onDrag callback | ||
var onDrag = this.options.onDrag; | ||
if (onDrag && typeof onDrag === 'function') onDrag(this.dragEl, e, evt); // Init in the move event to prevent conflict with the click event | ||
this._dispatchEvent('onChange', _objectSpread2(_objectSpread2({}, differ), {}, { | ||
event: e, | ||
originalEvent: evt | ||
})); | ||
} else { | ||
var _getElement2 = getElement(rootEl, target), | ||
el = _getElement2.el, | ||
rect = _getElement2.rect, | ||
offset = _getElement2.offset; | ||
var rect = this.differ.from.rect; | ||
var ghostEl = this.dragEl.cloneNode(true); | ||
this.ghost.init(ghostEl, rect, !this.nativeDraggable); // add class for drag element | ||
if (!el || !dragEl || el && el.animated) return; | ||
if (el === dragEl) return; | ||
dropEl = el; | ||
differ.to = { | ||
sortable: this, | ||
group: this.el, | ||
node: dropEl, | ||
rect: rect, | ||
offset: offset | ||
}; | ||
var clientX = e.clientX, | ||
clientY = e.clientY; | ||
var left = rect.left, | ||
right = rect.right, | ||
top = rect.top, | ||
bottom = rect.bottom; // swap when the elements before and after the drag are inconsistent | ||
toggleClass(this.dragEl, this.options.chosenClass, true); | ||
this.dragEl.style['will-change'] = 'transform'; | ||
if (Safari) css(document.body, 'user-select', 'none'); | ||
if (this.nativeDraggable) this._unbindDropEvents(); | ||
} | ||
}, | ||
_onChange: debounce(function (_this, target, e, evt) { | ||
var _getElement2 = getElement(_this.rootEl, target), | ||
el = _getElement2.el, | ||
rect = _getElement2.rect, | ||
offset = _getElement2.offset; | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
if (rootEl !== this.el) { | ||
if (nextEl) { | ||
this.el.insertBefore(dragEl, nextEl); | ||
} else { | ||
this.el.appendChild(dragEl); | ||
} // onChange callback | ||
if (!el || el && el.animated) return; | ||
_this.dropEl = el; | ||
var clientX = e.clientX, | ||
clientY = e.clientY; | ||
var left = rect.left, | ||
right = rect.right, | ||
top = rect.top, | ||
bottom = rect.bottom; | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
// swap when the elements before and after the drag are inconsistent | ||
if (el !== _this.dragEl) { | ||
_this.differ.to = { | ||
node: _this.dropEl, | ||
rect: rect, | ||
offset: offset | ||
}; | ||
this._dispatchEvent('onChange', _objectSpread2(_objectSpread2({}, differ), {}, { | ||
event: e, | ||
originalEvent: evt | ||
})); | ||
} else { | ||
this._captureAnimationState(dragEl, dropEl); // onChange callback | ||
_this.captureAnimationState(); | ||
var onChange = _this.options.onChange; | ||
this._dispatchEvent('onChange', _objectSpread2(_objectSpread2({}, differ), {}, { | ||
event: e, | ||
originalEvent: evt | ||
})); // the top value is compared first, and the left is compared if the top value is the same | ||
var _offset = getOffset(_this.dragEl); // onChange callback | ||
var _offset = getOffset(dragEl); | ||
if (onChange && typeof onChange === 'function') onChange(_this.differ.from, _this.differ.to, e, evt); // the top value is compared first, and the left is compared if the top value is the same | ||
if (_offset.top < offset.top || _offset.left < offset.left) { | ||
this.el.insertBefore(dragEl, el.nextElementSibling); | ||
} else { | ||
this.el.insertBefore(dragEl, el); | ||
} | ||
if (_offset.top < offset.top || _offset.left < offset.left) { | ||
_this.rootEl.insertBefore(_this.dragEl, el.nextElementSibling); | ||
} else { | ||
_this.rootEl.insertBefore(_this.dragEl, el); | ||
this._rangeAnimate(); | ||
} | ||
_this.animateRange(); | ||
} | ||
@@ -1237,40 +1458,79 @@ } | ||
this._preventEvent(evt); | ||
this.dragStartTimer && clearTimeout(this.dragStartTimer); | ||
var stopPropagation = this.options.stopPropagation; | ||
stopPropagation && evt.stopPropagation(); | ||
evt.preventDefault && evt.preventDefault(); | ||
var _getEvent3 = getEvent(evt), | ||
touch = _getEvent3.touch; // clear style and class | ||
if (dragEl) { | ||
if (this.nativeDraggable) off(dragEl, 'dragend', this); | ||
var _getEvent3 = getEvent(evt), | ||
touch = _getEvent3.touch; // clear style, attrs and class | ||
toggleClass(this.dragEl, this.options.chosenClass, false); | ||
if (this.nativeDraggable) this.dragEl.draggable = false; | ||
if (touch) this.dragEl.style['touch-action'] = ''; | ||
this.dragEl.style['will-change'] = ''; | ||
if (this.state.sortableDown && this.state.sortableMove) { | ||
// re-acquire the offset and rect values of the dragged element as the value after the drag is completed | ||
this.differ.to.offset = getOffset(this.dragEl); | ||
this.differ.to.rect = getRect(this.dragEl); | ||
var _this$differ = this.differ, | ||
from = _this$differ.from, | ||
to = _this$differ.to; // compare whether the element is swapped by offset | ||
toggleClass(dragEl, this.options.chosenClass, false); | ||
if (this.nativeDraggable) dragEl.draggable = false; | ||
if (touch) dragEl.style['touch-action'] = ''; | ||
dragEl.style['will-change'] = ''; | ||
var changed = from.offset.top !== to.offset.top || from.offset.left !== to.offset.left; // onDrop callback | ||
if (state.sortableDown && state.sortableMove) { | ||
// re-acquire the offset and rect values of the dragged element as the value after the drag is completed | ||
differ.to.offset = getOffset(dragEl); | ||
differ.to.rect = getRect(dragEl); | ||
var changed = offsetChanged(differ.from.offset, differ.to.offset); | ||
var onDrop = this.options.onDrop; | ||
if (onDrop && typeof onDrop === 'function') onDrop(changed, evt); | ||
this._dispatchEvent('onDrop', { | ||
changed: changed, | ||
event: evt, | ||
originalEvent: evt | ||
}); | ||
} | ||
} | ||
if (Safari) css(document.body, 'user-select', ''); | ||
this.ghost.destroy(this.differ.to.rect); | ||
this.state = new State(); | ||
this.ghost.destroy(differ.to.rect); | ||
this._clearState(); | ||
}, | ||
// -------------------------------- event ---------------------------------- | ||
_preventEvent: function _preventEvent(evt) { | ||
if (this.options.stopPropagation) evt.stopPropagation && evt.stopPropagation(); // prevent events from bubbling | ||
evt.preventDefault !== void 0 && evt.cancelable && evt.preventDefault(); | ||
}, | ||
_dispatchEvent: function _dispatchEvent(event, params) { | ||
var callback = this.options[event]; | ||
if (typeof callback === 'function') callback(params); | ||
}, | ||
// -------------------------------- clear ---------------------------------- | ||
_clearState: function _clearState() { | ||
this.state = new State(); | ||
this.differ.destroy(); | ||
this.dragEl = null; | ||
this.dropEl = null; | ||
state = new State(); | ||
differ.destroy(); | ||
dragEl = dropEl = nextEl = ghostEl = activeGroup = null; | ||
move = lastPosition = { | ||
x: 0, | ||
y: 0 | ||
}; | ||
}, | ||
_unbindDragEvents: function _unbindDragEvents() { | ||
if (this.nativeDraggable) { | ||
off(this.el, 'dragstart', this._onDragStart); | ||
off(this.el, 'dragover', this._onDragOver); | ||
off(this.el, 'dragend', this._onDrop); | ||
off(document, 'drop', this); | ||
} | ||
}, | ||
_unbindMoveEvents: function _unbindMoveEvents() { | ||
off(this.ownerDocument, 'pointermove', this._onMove); | ||
off(this.ownerDocument, 'touchmove', this._onMove); | ||
off(this.ownerDocument, 'mousemove', this._onMove); | ||
off(this.ownerDocument, 'touchmove', _nearestSortable); | ||
off(this.ownerDocument, 'mousemove', _nearestSortable); | ||
off(this.ownerDocument, 'dragover', _nearestSortable); | ||
}, | ||
_unbindDropEvents: function _unbindDropEvents() { | ||
off(this.ownerDocument, 'pointerup', this._onDrop); | ||
off(this.ownerDocument, 'pointercancel', this._onDrop); | ||
off(this.ownerDocument, 'touchend', this._onDrop); | ||
off(this.ownerDocument, 'touchcancel', this._onDrop); | ||
off(this.ownerDocument, 'mouseup', this._onDrop); | ||
} | ||
@@ -1282,4 +1542,3 @@ }; | ||
debounce: debounce, | ||
throttle: throttle, | ||
getParentAutoScrollElement: getParentAutoScrollElement | ||
throttle: throttle | ||
}; | ||
@@ -1286,0 +1545,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 s(t){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var o=0;o<e.length;o++){var n=e[o];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function i(t,e,o){return e&&n(t.prototype,e),o&&n(t,o),Object.defineProperty(t,"prototype",{writable:!1}),t}function r(t){return function(t){if(Array.isArray(t))return a(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 a(t,e);var o=Object.prototype.toString.call(t).slice(8,-1);return"Map"===(o="Object"===o&&t.constructor?t.constructor.name:o)||"Set"===o?Array.from(t):"Arguments"===o||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(o)?a(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 a(t,e){(null==e||e>t.length)&&(e=t.length);for(var o=0,n=new Array(e);o<e;o++)n[o]=t[o];return n}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var e,l=t(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),h=t(/Edge/i),c=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),u=t(/iP(ad|od|hone)/i),f=t(/chrome/i)&&t(/android/i),d={capture:!1,passive:!1},p=/\s+/g,g=["-webkit-transition","-moz-transition","-ms-transition","-o-transition","transition"],m=["-webkit-transform","-moz-transform","-ms-transform","-o-transform","transform"],v=(e=!1,document.addEventListener("checkIfSupportPassive",null,{get passive(){return e=!0}}),e);function y(e,o){o?"none"===o?g.forEach(function(t){return P(e,t,"none")}):g.forEach(function(t){return P(e,t,"".concat(t.split("transition")[0],"transform ").concat(o))}):g.forEach(function(t){return P(e,t,"")})}function b(e,o){o?m.forEach(function(t){return P(e,t,"".concat(t.split("transform")[0]).concat(o))}):m.forEach(function(t){return P(e,t,"")})}function w(t){var e=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,t=e||t;return{touch:e,e:t,target:e?document.elementFromPoint(t.clientX,t.clientY):t.target}}function E(t,e,o){window.addEventListener?t.addEventListener(e,o,!(!v&&l)&&d):window.attachEvent&&t.attachEvent("on"+e,o)}function D(t,e,o){window.removeEventListener?t.removeEventListener(e,o,!(!v&&l)&&d):window.detachEvent&&t.detachEvent("on"+e,o)}function _(t){for(var e={top:0,left:0,height:0,width:0},o=(e.height=t.offsetHeight,e.width=t.offsetWidth,e.top=t.offsetTop,e.left=t.offsetLeft,t.offsetParent);null!==o;)e.top+=o.offsetTop,e.left+=o.offsetLeft,o=o.offsetParent;return e}function S(t,e){if(!t||!t.getBoundingClientRect)return T();var o=t,n=!1;do{if(o.clientWidth<o.scrollWidth||o.clientHeight<o.scrollHeight){var i=P(o);if(o.clientWidth<o.scrollWidth&&("auto"==i.overflowX||"scroll"==i.overflowX)||o.clientHeight<o.scrollHeight&&("auto"==i.overflowY||"scroll"==i.overflowY)){if(!o.getBoundingClientRect||o===document.body)return T();if(n||e)return o;n=!0}}}while(o=o.parentNode);return T()}function T(){var t=document.scrollingElement;return!t||t.contains(document.body)?document:t}function x(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!==T()?(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}function $(t,e,o){var n=r(Array.from(t.children)),t=n.indexOf(e);if(-1<t)return o?n[t]:{index:t,el:n[t],rect:x(n[t]),offset:_(n[t])};for(var i=0;i<n.length;i++)if(function(t,e){var o;if(t&&e)for(o=t.parentNode;o;){if(e===o)return 1;o=o.parentNode}return}(e,n[i]))return o?n[i]:{index:i,el:n[i],rect:x(n[i]),offset:_(n[i])};return o?null:{index:-1,el:null,rect:{},offset:{}}}function M(t,e,o){var n;t&&e&&(t.classList?t.classList[o?"add":"remove"](e):(n=(" "+t.className+" ").replace(p," ").replace(" "+e+" "," "),t.className=(n+(o?" "+e:"")).replace(p," ")))}function P(t,e,o){var n=t&&t.style;if(n){if(void 0===o)return document.defaultView&&document.defaultView.getComputedStyle?o=document.defaultView.getComputedStyle(t,""):t.currentStyle&&(o=t.currentStyle),void 0===e?o:o[e];n[e=e in n||-1!==e.indexOf("webkit")?e:"-webkit-"+e]=o+("string"==typeof o?"":"px")}}function A(o,n,i){var r=null;return function(){var t=this,e=arguments;r&&clearTimeout(r),i&&!r&&o.apply(t,e),r=setTimeout(function(){o.apply(t,e)},n)}}function O(o,n){var i=null;return function(){var t=this,e=arguments;i=i||setTimeout(function(){i=null,o.apply(t,e)},n)}}var k=i(function t(){o(this,t),this.sortableDown=void 0,this.sortableMove=void 0,this.animationEnd=void 0}),C=function(){function t(){o(this,t),this.from={node:null,rect:{},offset:{}},this.to={node:null,rect:{},offset:{}}}return i(t,[{key:"get",value:function(t){return this[t]}},{key:"set",value:function(t,e){this[t]=e}},{key:"destroy",value:function(){this.from={node:null,rect:{},offset:{}},this.to={node:null,rect:{},offset:{}}}}]),t}(),L=function(){function e(t){o(this,e),this.$el=null,this.distance={x:0,y:0},this.options=t.options,this.container=t.container}return i(e,[{key:"init",value:function(t,e){var o=!(2<arguments.length&&void 0!==arguments[2])||arguments[2],t=(this.$el=t,this.options),n=t.ghostClass,t=t.ghostStyle,t=void 0===t?{}:t;M(this.$el,n,!0),P(this.$el,"box-sizing","border-box"),P(this.$el,"margin",0),P(this.$el,"top",e.top),P(this.$el,"left",e.left),P(this.$el,"width",e.width),P(this.$el,"height",e.height),P(this.$el,"opacity","0.8"),P(this.$el,"position","fixed"),P(this.$el,"zIndex","100000"),P(this.$el,"pointerEvents","none"),this.setStyle(t),y(this.$el,"none"),b(this.$el,"translate3d(0px, 0px, 0px)"),o&&this.container.appendChild(this.$el),P(this.$el,"transform-origin",this.distance.x/parseInt(this.$el.style.width)*100+"% "+this.distance.y/parseInt(this.$el.style.height)*100+"%")}},{key:"setStyle",value:function(t){for(var e in t)P(this.$el,e,t[e])}},{key:"rect",value:function(){return x(this.$el)}},{key:"move",value:function(t,e){this.$el&&(y(this.$el,2<arguments.length&&void 0!==arguments[2]&&arguments[2]?"".concat(this.options.ghostAnimation,"ms"):"none"),b(this.$el,"translate3d(".concat(t,"px, ").concat(e,"px, 0)")))}},{key:"destroy",value:function(t){var e,o,n=this;this.$el&&(o=parseInt(this.$el.style.left),e=parseInt(this.$el.style.top),this.move(t.left-o,t.top-e,!0),(o=this.options.ghostAnimation)?setTimeout(function(){return n.clear()},o):this.clear())}},{key:"clear",value:function(){this.$el&&this.$el.remove(),this.distance={x:0,y:0},this.$el=null}}]),e}();function I(){var i=[];return{captureAnimationState:function(){var t=r(Array.from(this.rootEl.children)),e=(o=t,n=this.dragEl,e=this.dropEl,n=o.indexOf(n),o=o.indexOf(e),n<o?{start:n,end:o}:{start:o,end:n}),o=e.start,n=e.end;i.length=0,t.slice(o,n+1).forEach(function(t){i.push({target:t,rect:x(t)})})},animateRange:function(){var o=this;i.forEach(function(t){var e=t.target,t=t.rect;o.animate(e,t,o.options.animation)})},animate:function(t,e){var o=2<arguments.length&&void 0!==arguments[2]?arguments[2]:150,n=x(t),i=e.left-n.left,e=e.top-n.top;y(t,"none"),b(t,"translate3d(".concat(i,"px, ").concat(e,"px, 0)")),t.offsetLeft,y(t,"".concat(o,"ms")),b(t,"translate3d(0px, 0px, 0px)"),clearTimeout(t.animated),t.animated=setTimeout(function(){y(t,""),b(t,""),t.animated=null},o)}}}var W="undefined"!=typeof document&&!f&&!u&&"draggable"in document.createElement("div");function H(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));this.rootEl=t,this.scrollEl=S(t,!0),this.options=e=Object.assign({},e),this.ownerDocument=t.ownerDocument;var o,n={autoScroll:!0,scrollStep:5,scrollThreshold:15,delay:0,delayOnTouchOnly:!1,disabled:!1,animation:150,ghostAnimation:0,ghostClass:"",ghostStyle:{},chosenClass:"",draggable:void 0,dragging:void 0,onDrag:void 0,onMove:void 0,onDrop:void 0,onChange:void 0,fallbackOnBody:!1,forceFallback:!1,stopPropagation:!1,supportPointer:"PointerEvent"in window&&!c,supportTouch:"ontouchstart"in window};for(o in n)o in this.options||(this.options[o]=n[o]);this.container=this.options.fallbackOnBody?document.body:this.rootEl,this.nativeDraggable=!this.options.forceFallback&&W,this.move={x:0,y:0},this.state=new k,this.differ=new C,this.ghost=new L(this),this.dragEl=null,this.dropEl=null,this.dragStartTimer=null,this.autoScrollTimer=null,Object.assign(this,{_bindEventListener:function(){this._onDrag=this._onDrag.bind(this),this._onMove=this._onMove.bind(this),this._onDrop=this._onDrop.bind(this);var t=this.options,e=t.supportPointer,t=t.supportTouch;E(this.rootEl,e?"pointerdown":t?"touchstart":"mousedown",this._onDrag)},_clearEvent:function(){D(this.rootEl,"pointerdown",this._onDrag),D(this.rootEl,"touchstart",this._onDrag),D(this.rootEl,"mousedown",this._onDrag)},_bindMoveEvents:function(t){this.options.supportPointer?E(this.ownerDocument,"pointermove",this._onMove):E(this.ownerDocument,t?"touchmove":"mousemove",this._onMove)},_unbindMoveEvents:function(){D(this.ownerDocument,"pointermove",this._onMove),D(this.ownerDocument,"touchmove",this._onMove),D(this.ownerDocument,"mousemove",this._onMove)},_unbindDropEvents:function(){D(this.ownerDocument,"pointerup",this._onDrop),D(this.ownerDocument,"pointercancel",this._onDrop),D(this.ownerDocument,"touchend",this._onDrop),D(this.ownerDocument,"touchcancel",this._onDrop),D(this.ownerDocument,"mouseup",this._onDrop)},_unbindDragEvents:function(){this.nativeDraggable&&(D(this.rootEl,"dragstart",this._onDragStart),D(this.rootEl,"dragover",this._onDragOver),D(this.rootEl,"dragend",this._onDrop))}},I(),(window.requestAnimationFrame||(window.requestAnimationFrame=function(t){return setTimeout(t,17)}),{_autoScroll:O(function(t){var e,o,n,i,r,s,a,l,h,c,u,f,d,p,g;t.state.sortableDown&&t.state.sortableMove&&(e=(o=t.state.sortableMove).clientX,o=o.clientY,void 0!==e&&void 0!==o&&t.scrollEl!==t.ownerDocument&&(n=(p=t.scrollEl).scrollTop,i=p.scrollLeft,r=p.scrollHeight,p=p.scrollWidth,s=(d=x(t.scrollEl)).top,u=d.right,a=d.bottom,f=d.left,l=d.height,d=d.width,h=(c=t.options).scrollStep,c=c.scrollThreshold,f=0<i&&f<=e&&e<=f+c,d=i+d<p&&e<=u&&u-c<=e,p=n+l<r&&o<=a&&a-c<=o,g={x:i,y:n},(u=0<n&&s<=o&&o<=s+c)?(g.x=f?i-h:d?i+h:i,g.y=n-h):p?(g.x=f?i-h:d?i+h:i,g.y=n+h):f?(g.x=i-h,g.y=n):d&&(g.x=i+h,g.y=n),(u||f||d||p)&&requestAnimationFrame(function(){t.scrollEl.scrollTo(g.x,g.y),t._autoScroll(t)})))},10)})),this._bindEventListener()}return(H.prototype={constructor:H,destroy:function(){this._clearState(),this._clearEvent(),Array.prototype.forEach.call(this.rootEl.querySelectorAll("[draggable]"),function(t){t.removeAttribute("draggable")})},set:function(t,e){this.options[t]=e},get:function(t){return this.options[t]},_onDrag:function(t){var e=this;if(!(/mousedown|pointerdown/.test(t.type)&&0!==t.button||this.options.disabled)){var o=w(t),n=o.touch,i=o.e,o=o.target;if(this.nativeDraggable||!c||!o||"SELECT"!==o.tagName.toUpperCase()){if(o===this.rootEl)return!0;this.options.stopPropagation&&t.stopPropagation();var t=this.options,r=t.draggable,t=t.dragging;if("function"==typeof r){if(!r(i))return!0}else if("string"==typeof r){if(!function(t,e){if(e&&(">"===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}}(o,r))return!0}else if(void 0!==r)throw new Error('draggable expected "function" or "string" but received "'.concat(s(r),'"'));if(t){if("function"!=typeof t)throw new Error('dragging expected "function" or "string" but received "'.concat(s(t),'"'));this.dragEl=t(i)}else this.dragEl=$(this.rootEl,o,!0);if(!this.dragEl||this.dragEl.animated)return!0;n&&(this.dragEl.style["touch-action"]="none");r=$(this.rootEl,this.dragEl),t=r.rect,o=r.offset,r=(this.move={x:i.clientX,y:i.clientY},this.differ.from={node:this.dragEl,rect:t,offset:o},this.ghost.distance={x:i.clientX-t.left,y:i.clientY-t.top},this.state.sortableDown=i,E(this.ownerDocument,"pointerup",this._onDrop),E(this.ownerDocument,"touchend",this._onDrop),E(this.ownerDocument,"mouseup",this._onDrop),this.options),o=r.delay,t=r.delayOnTouchOnly;!o||t&&!n||this.nativeDraggable&&(h||l)?this._onStart(i,n):(clearTimeout(this.dragStartTimer),this.dragStartTimer=setTimeout(function(){return e._onStart(i,n)},o))}}},_onStart:function(t,e){!this.nativeDraggable||e?(this._bindMoveEvents(e),E(this.ownerDocument,"pointercancel",this._onDrop),E(this.ownerDocument,"touchcancel",this._onDrop)):(this.dragEl.draggable=!0,this._onDragStart=this._onDragStart.bind(this),this._onDragOver=this._onDragOver.bind(this),E(this.rootEl,"dragstart",this._onDragStart));try{document.selection?setTimeout(function(){document.selection.empty()},0):window.getSelection().removeAllRanges()}catch(t){}},_onDragStart:function(t){t.dataTransfer.setData("te",t.target.innerText),E(this.rootEl,"dragover",this._onDragOver),E(this.rootEl,"dragend",this._onDrop)},_onDragOver:function(t){var e,o,n,i;this.state.sortableDown&&(this.options.stopPropagation&&t.stopPropagation&&t.stopPropagation(),void 0!==t.preventDefault&&t.cancelable&&t.preventDefault(),e=t.clientX,o=t.clientY,n=e-this.move.x,i=o-this.move.y,void 0!==e&&Math.abs(n)<=0&&void 0!==o&&Math.abs(i)<=0||(this._onStarted(t,t),t.target!==this.rootEl&&this._onChange(this,t.target,t,t)))},_onMove:function(t){var e,o,n,i,r,s,a,l,h=this;this.state.sortableDown&&(e=(o=w(t)).e,o=o.target,n=e.clientX,i=e.clientY,s=n-this.move.x,r=i-this.move.y,void 0!==n&&Math.abs(s)<=0&&void 0!==i&&Math.abs(r)<=0||(this.options.stopPropagation&&t.stopPropagation&&t.stopPropagation(),void 0!==t.preventDefault&&t.cancelable&&t.preventDefault(),this._onStarted(e,t),this.ghost.move(s,r),(s=this.options.onMove)&&"function"==typeof s&&s(this.differ.from,this.ghost.$el,e,t),n<0||i<0||(s=(r=x(this.rootEl)).top,a=r.right,l=r.bottom,n<r.left||a<n||i<s||l<i||(this._onChange(this,o,e,t),this.autoScrollTimer&&clearTimeout(this.autoScrollTimer),this.options.autoScroll&&(this.autoScrollTimer=setTimeout(function(){return h._autoScroll(h)},0))))))},_onStarted:function(t,e){var o;this.state.sortableMove=t,this.ghost.$el||((o=this.options.onDrag)&&"function"==typeof o&&o(this.dragEl,t,e),o=this.differ.from.rect,t=this.dragEl.cloneNode(!0),this.ghost.init(t,o,!this.nativeDraggable),M(this.dragEl,this.options.chosenClass,!0),this.dragEl.style["will-change"]="transform",c&&P(document.body,"user-select","none"),this.nativeDraggable&&this._unbindDropEvents())},_onChange:A(function(t,e,o,n){var i,r,s,a,l,h,e=$(t.rootEl,e),c=e.el,u=e.rect,e=e.offset;c&&!c.animated&&(t.dropEl=c,h=o.clientX,i=o.clientY,l=u.left,r=u.right,s=u.top,a=u.bottom,l<h&&h<r&&s<i&&i<a&&c!==t.dragEl&&(t.differ.to={node:t.dropEl,rect:u,offset:e},t.captureAnimationState(),l=t.options.onChange,h=_(t.dragEl),l&&"function"==typeof l&&l(t.differ.from,t.differ.to,o,n),h.top<e.top||h.left<e.left?t.rootEl.insertBefore(t.dragEl,c.nextElementSibling):t.rootEl.insertBefore(t.dragEl,c),t.animateRange()))},5),_onDrop:function(t){this._unbindDragEvents(),this._unbindMoveEvents(),this._unbindDropEvents(),this.dragStartTimer&&clearTimeout(this.dragStartTimer),this.options.stopPropagation&&t.stopPropagation(),t.preventDefault&&t.preventDefault();var e,o=w(t).touch;M(this.dragEl,this.options.chosenClass,!1),this.nativeDraggable&&(this.dragEl.draggable=!1),o&&(this.dragEl.style["touch-action"]=""),this.dragEl.style["will-change"]="",this.state.sortableDown&&this.state.sortableMove&&(this.differ.to.offset=_(this.dragEl),this.differ.to.rect=x(this.dragEl),e=(o=this.differ).from,o=o.to,e=e.offset.top!==o.offset.top||e.offset.left!==o.offset.left,(o=this.options.onDrop)&&"function"==typeof o&&o(e,t)),c&&P(document.body,"user-select",""),this.ghost.destroy(this.differ.to.rect),this.state=new k},_clearState:function(){this.state=new k,this.differ.destroy(),this.dragEl=null,this.dropEl=null}}).utils={getRect:x,getOffset:_,debounce:A,throttle:O,getParentAutoScrollElement:S},H}); | ||
!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 e(e,t){var n,o=Object.keys(e);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(e),t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),o.push.apply(o,n)),o}function h(o){for(var t=1;t<arguments.length;t++){var i=null!=arguments[t]?arguments[t]:{};t%2?e(Object(i),!0).forEach(function(t){var e,n;e=o,n=i[t=t],t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n}):Object.getOwnPropertyDescriptors?Object.defineProperties(o,Object.getOwnPropertyDescriptors(i)):e(Object(i)).forEach(function(t){Object.defineProperty(o,t,Object.getOwnPropertyDescriptor(i,t))})}return o}function a(t){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(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 o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function i(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}function W(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,o=new Array(e);n<e;n++)o[n]=t[n];return o}function t(t){if("undefined"!=typeof window&&window.navigator)return!!navigator.userAgent.match(t)}var s,l=t(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),X=t(/Edge/i),c=t(/safari/i)&&!t(/chrome/i)&&!t(/android/i),Y=t(/iP(ad|od|hone)/i),B=t(/chrome/i)&&t(/android/i),H={capture:!1,passive:!1},N=/\s+/g,u=["-webkit-transition","-moz-transition","-ms-transition","-o-transition","transition"],F=["-webkit-transform","-moz-transform","-ms-transform","-o-transform","transform"],R=(s=!1,document.addEventListener("checkIfSupportPassive",null,{get passive(){return s=!0}}),s);function f(e,n){n?"none"===n?u.forEach(function(t){return E(e,t,"none")}):u.forEach(function(t){return E(e,t,"".concat(t.split("transition")[0],"transform ").concat(n))}):u.forEach(function(t){return E(e,t,"")})}function d(e,n){n?F.forEach(function(t){return E(e,t,"".concat(t.split("transform")[0]).concat(n))}):F.forEach(function(t){return E(e,t,"")})}function p(t){var e=t.touches&&t.touches[0]||t.pointerType&&"touch"===t.pointerType&&t,t=e||t;return{touch:e,e:t,target:e?document.elementFromPoint(t.clientX,t.clientY):t.target}}function g(t,e,n){window.addEventListener?t.addEventListener(e,n,!(!R&&l)&&H):window.attachEvent&&t.attachEvent("on"+e,n)}function m(t,e,n){window.removeEventListener?t.removeEventListener(e,n,!(!R&&l)&&H):window.detachEvent&&t.detachEvent("on"+e,n)}function v(t){for(var e={top:0,left:0,height:0,width:0},n=(e.height=t.offsetHeight,e.width=t.offsetWidth,e.top=t.offsetTop,e.left=t.offsetLeft,t.offsetParent);null!==n;)e.top+=n.offsetTop,e.left+=n.offsetLeft,n=n.offsetParent;return e}function b(){var t=document.scrollingElement;return!t||t.contains(document.body)?document:t}function y(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!==b()?(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}function w(t,e,n){var o=W(Array.from(t.children)),t=o.indexOf(e);if(-1<t)return n?o[t]:{index:t,el:o[t],rect:y(o[t]),offset:v(o[t])};for(var i=0;i<o.length;i++)if(function(t,e){var n;if(t&&e)for(n=t.parentNode;n;){if(e===n)return 1;n=n.parentNode}return}(e,o[i]))return n?o[i]:{index:i,el:o[i],rect:y(o[i]),offset:v(o[i])};return n?null:{index:-1,el:null,rect:{},offset:{}}}function D(t,e,n){var o;t&&e&&(t.classList?t.classList[n?"add":"remove"](e):(o=(" "+t.className+" ").replace(N," ").replace(" "+e+" "," "),t.className=(o+(n?" "+e:"")).replace(N," ")))}function q(t,e){if(e&&(">"===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}}function E(t,e,n){var o=t&&t.style;if(o){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];o[e=e in o||-1!==e.indexOf("webkit")?e:"-webkit-"+e]=n+("string"==typeof n?"":"px")}}function z(n,o,i){var r=null;return function(){var t=this,e=arguments;r&&clearTimeout(r),i&&!r&&n.apply(t,e),r=setTimeout(function(){n.apply(t,e)},o)}}function V(n,o){var i=null;return function(){var t=this,e=arguments;i=i||setTimeout(function(){i=null,n.apply(t,e)},o)}}var _="Sortable"+Date.now(),U=i(function t(){n(this,t),this.sortableDown=void 0,this.sortableMove=void 0,this.animationEnd=void 0}),Z=function(){function t(){n(this,t),this.from={sortable:null,group:null,node:null,rect:{},offset:{}},this.to={sortable:null,group:null,node:null,rect:{},offset:{}}}return i(t,[{key:"destroy",value:function(){this.from={sortable:null,group:null,node:null,rect:{},offset:{}},this.to={sortable:null,group:null,node:null,rect:{},offset:{}}}}]),t}(),$=function(){function e(t){n(this,e),this.el=null,this.distance={x:0,y:0},this.options=t.options,this.container=t.container}return i(e,[{key:"init",value:function(t,e){var n=!(2<arguments.length&&void 0!==arguments[2])||arguments[2];this.el=t,n&&(n=(t=this.options).ghostClass,t=void 0===(t=t.ghostStyle)?{}:t,D(this.el,n,!0),E(this.el,"box-sizing","border-box"),E(this.el,"margin",0),E(this.el,"top",e.top),E(this.el,"left",e.left),E(this.el,"width",e.width),E(this.el,"height",e.height),E(this.el,"opacity","0.8"),E(this.el,"position","fixed"),E(this.el,"zIndex","100000"),E(this.el,"pointerEvents","none"),this.setStyle(t),f(this.el,"none"),d(this.el,"translate3d(0px, 0px, 0px)"),this.container.appendChild(this.el),E(this.el,"transform-origin",this.distance.x/parseInt(this.el.style.width)*100+"% "+this.distance.y/parseInt(this.el.style.height)*100+"%"),E(this.el,"transform","translateZ(0)"))}},{key:"setStyle",value:function(t){for(var e in t)E(this.el,e,t[e])}},{key:"rect",value:function(){return y(this.el)}},{key:"move",value:function(t,e){this.el&&(f(this.el,2<arguments.length&&void 0!==arguments[2]&&arguments[2]?"".concat(this.options.ghostAnimation,"ms"):"none"),d(this.el,"translate3d(".concat(t,"px, ").concat(e,"px, 0)")))}},{key:"clear",value:function(){this.distance={x:0,y:0},this.el&&this.el.remove(),this.el=null}},{key:"destroy",value:function(t){var e,n,o=this;this.el&&(n=parseInt(this.el.style.left),e=parseInt(this.el.style.top),this.move(t.left-n,t.top-e,!0),(n=this.options.ghostAnimation)?setTimeout(function(){return o.clear()},n):this.clear())}}]),e}();function G(){var i=[];return{_captureAnimationState:function(t,e){var n=W(Array.from(this.el.children)),e=(t=t,e=e,t=(o=n).indexOf(t),o=o.indexOf(e),t<o?{start:t,end:o}:{start:o,end:t}),o=e.start,t=e.end;i.length=0,n.slice(o,t+1).forEach(function(t){i.push({target:t,rect:y(t)})})},_rangeAnimate:function(){var n=this;i.forEach(function(t){var e=t.target,t=t.rect;n._animate(e,t,n.options.animation)})},_animate:function(t,e){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:150,o=y(t),i=e.left-o.left,e=e.top-o.top;f(t,"none"),d(t,"translate3d(".concat(i,"px, ").concat(e,"px, 0)")),t.offsetWidth,f(t,"".concat(n,"ms")),d(t,"translate3d(0px, 0px, 0px)"),clearTimeout(t.animated),t.animated=setTimeout(function(){f(t,""),d(t,""),t.animated=null},n)}}}function S(t){if(K(t),x){var e=t=t.touches?t.touches[0]:t,n=e.clientX,e=e.clientY,o=J(n,e);if(o){var i,r={};for(i in t)r[i]=t[i];r.target=document.elementFromPoint(n,e),r.rootEl=o,r.preventDefault=void 0,r.stopPropagation=void 0,o[_]._triggerEvent(r)}}}function J(i,r){var s;return tt.some(function(t){var e,n,o=t[_].options.emptyInsertThreshold;if(o)return n=y(t),e=i>=n.left-o&&i<=n.right+o,n=r>=n.top-o&&r<=n.bottom+o,e&&n?s=t:void 0}),s}function K(t){var e=t.clientX,t=t.clientY,n=e-L.x,o=t-L.y;L.x=e,L.y=t,void 0!==e&&Math.abs(n)<1&&void 0!==t&&Math.abs(o)}var T,x,O,P,C,M,Q="undefined"!=typeof document&&!B&&!Y&&"draggable"in document.createElement("div"),tt=[],A={x:0,y:0},j=new U,k=new Z,L={x:0,y:0};function I(t,e){if(!t||!t.nodeType||1!==t.nodeType)throw"Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(t));(t[_]=this).el=t,this.scrollEl=function(t,e){if(!t||!t.getBoundingClientRect)return b();var n=t,o=!1;do{if(n.clientWidth<n.scrollWidth||n.clientHeight<n.scrollHeight){var i=E(n);if(n.clientWidth<n.scrollWidth&&("auto"==i.overflowX||"scroll"==i.overflowX)||n.clientHeight<n.scrollHeight&&("auto"==i.overflowY||"scroll"==i.overflowY)){if(!n.getBoundingClientRect||n===document.body)return b();if(o||e)return n;o=!0}}}while(n=n.parentNode);return b()}(t,!0),this.options=e=Object.assign({},e),this.ownerDocument=t.ownerDocument;var n,o,i={group:"",animation:150,draggable:void 0,onDrag:void 0,onMove:void 0,onDrop:void 0,onChange:void 0,autoScroll:!0,scrollStep:5,scrollThreshold:15,delay:0,delayOnTouchOnly:!1,disabled:!1,ghostAnimation:0,ghostClass:"",ghostStyle:{},chosenClass:"",fallbackOnBody:!1,forceFallback:!1,stopPropagation:!1,supportPointer:"PointerEvent"in window&&!c,supportTouch:"ontouchstart"in window,emptyInsertThreshold:5};for(n in i)n in this.options||(this.options[n]=i[n]);for(o in this.container=this.options.fallbackOnBody?document.body:t,this.nativeDraggable=!this.options.forceFallback&&Q,this.ghost=new $(this),this.dragStartTimer=null,this.autoScrollTimer=null,s={},(r=(e=e).group)&&"object"==a(r)||(r={name:r}),s.name=r.name,s.pull=r.pull,s.put=r.put,e.group=s,this)"_"===o.charAt(0)&&"function"==typeof this[o]&&(this[o]=this[o].bind(this));var r=this.options,e=r.supportPointer,s=r.supportTouch;g(t,e?"pointerdown":s?"touchstart":"mousedown",this._onDrag),this.nativeDraggable&&(g(t,"dragover",this),g(t,"dragenter",this)),tt.push(t),Object.assign(this,G(),(window.requestAnimationFrame||(window.requestAnimationFrame=function(t){return setTimeout(t,17)}),{_autoScroll:V(function(t,e){var n,o,i,r,s,a,l,c,h,u,f,d,p,g,m;t.scrollEl&&e.sortableDown&&e.sortableMove&&(n=(o=e.sortableMove).clientX,o=o.clientY,void 0!==n&&void 0!==o&&t.scrollEl!==t.ownerDocument&&(i=(g=t.scrollEl).scrollTop,r=g.scrollLeft,s=g.scrollHeight,g=g.scrollWidth,a=(p=y(t.scrollEl)).top,f=p.right,l=p.bottom,d=p.left,c=p.height,p=p.width,h=(u=t.options).scrollStep,u=u.scrollThreshold,d=0<r&&d<=n&&n<=d+u,p=r+p<g&&n<=f&&f-u<=n,g=i+c<s&&o<=l&&l-u<=o,m={x:r,y:i},(f=0<i&&a<=o&&o<=a+u)?(m.x=d?r-h:p?r+h:r,m.y=i-h):g?(m.x=d?r-h:p?r+h:r,m.y=i+h):d?(m.x=r-h,m.y=i):p&&(m.x=r+h,m.y=i),(f||d||p||g)&&requestAnimationFrame(function(){t.scrollEl.scrollTo(m.x,m.y),t._autoScroll(t,e)})))},10)}))}return(I.prototype={constructor:I,destroy:function(){this.el[_]=null,m(this.el,"pointerdown",this._onDrag),m(this.el,"touchstart",this._onDrag),m(this.el,"mousedown",this._onDrag),this.nativeDraggable&&(m(this.el,"dragover",this),m(this.el,"dragenter",this)),this._clearState(),Array.prototype.forEach.call(this.el.querySelectorAll("[draggable]"),function(t){t.removeAttribute("draggable")})},set:function(t,e){this.options[t]=e},get:function(t){return this.options[t]},_onDrag:function(t){var e=this;if(!(/mousedown|pointerdown/.test(t.type)&&0!==t.button||this.options.disabled)&&this.options.group.pull){var n=p(t),o=n.touch,i=n.e,n=n.target;if(this.nativeDraggable||!c||!n||"SELECT"!==n.tagName.toUpperCase()){if(n===this.el)return!0;this.options.stopPropagation&&t.stopPropagation&&t.stopPropagation();t=this.options.draggable;if("function"==typeof t){var r=t(i);if(!r)return!0;!function(e){var t=document.createElement("div");try{return t.appendChild(e.cloneNode(!0)),1==e.nodeType}catch(t){return e==window||e==document}}(r)||(x=r)}else if("string"==typeof t){if(!q(n,t))return!0}else if(t)throw new Error('draggable expected "function" or "string" but received "'.concat(a(t),'"'));if(!(x=x||w(this.el,n,!0))||x.animated)return!0;o&&(x.style["touch-action"]="none");r=w(this.el,x),t=r.rect,n=r.offset,r=(A={x:i.clientX,y:i.clientY},k.from={sortable:this,group:this.el,node:x,rect:t,offset:n},this.ghost.distance={x:i.clientX-t.left,y:i.clientY-t.top},j.sortableDown=i,g(this.ownerDocument,"dragover",S),g(this.ownerDocument,"mousemove",S),g(this.ownerDocument,"touchmove",S),g(this.ownerDocument,"pointerup",this._onDrop),g(this.ownerDocument,"touchend",this._onDrop),g(this.ownerDocument,"mouseup",this._onDrop),this.options),n=r.delay,t=r.delayOnTouchOnly;!n||t&&!o||this.nativeDraggable&&(X||l)?this._onStart(i,o):(clearTimeout(this.dragStartTimer),this.dragStartTimer=setTimeout(function(){return e._onStart(i,o)},n))}}},_onStart:function(t,e){T=this.el,P=x.nextSibling,M=this.options.group,!this.nativeDraggable||e?(this.options.supportPointer?g(this.ownerDocument,"pointermove",this._onMove):g(this.ownerDocument,e?"touchmove":"mousemove",this._onMove),g(this.ownerDocument,"pointercancel",this._onDrop),g(this.ownerDocument,"touchcancel",this._onDrop)):(x.draggable=!0,g(x,"dragend",this),g(this.el,"dragstart",this._onDragStart));try{document.selection?setTimeout(function(){document.selection.empty()},0):window.getSelection().removeAllRanges()}catch(t){}},_triggerEvent:function(t){M.name===this.options.group.name&&(T=t.rootEl,this.nativeDraggable?(g(this.el,"dragend",this._onDrop),this._onDragOver(t)):this._onMove(t))},_onDragStart:function(t){t.dataTransfer&&(t.dataTransfer.setData("draggableEffect",t.target.innerText),t.dataTransfer.effectAllowed="move"),g(this.el,"dragover",this._onDragOver),g(this.el,"dragend",this._onDrop)},_onDragOver:function(t){t.dataTransfer&&(t.dataTransfer.dropEffect="move"),j.sortableDown&&x&&(this._preventEvent(t),K(t),this._onStarted(t,t),this._dispatchEvent("onMove",h(h({},k),{},{ghostEl:C,event:t,originalEvent:t})),!this.options.group.put&&k.from.group!==this.el||this._onChange(t.target,t,t))},_onStarted:function(t,e){j.sortableMove=t,C||(this._dispatchEvent("onDrag",{dragEl:x,event:t,originalEvent:e}),t=k.from.rect,C=x.cloneNode(!0),this.ghost.init(C,t,!this.nativeDraggable),I.ghost=C,D(x,this.options.chosenClass,!0),x.style["will-change"]="transform",this.nativeDraggable&&(this._unbindDropEvents(),g(document,"drop",this)),c&&E(document.body,"user-select","none"))},_onMove:function(t){var e,n,o,i,r,s,a=this;j.sortableDown&&x&&((n=p(t)).touch,e=n.e,n=n.target,o=e.clientX,i=e.clientY,r=o-A.x,s=i-A.y,void 0!==o&&Math.abs(r)<=0&&void 0!==i&&Math.abs(s)<=0||(this._preventEvent(t),this._onStarted(e,t),this.ghost.move(r,s),this._dispatchEvent("onMove",h(h({},k),{},{ghostEl:C,event:e,originalEvent:t})),this._onChange(n,e,t),clearTimeout(this.autoScrollTimer),this.options.autoScroll&&(this.autoScrollTimer=setTimeout(function(){return a._autoScroll(a,j)},0))))},_onChange:z(function(t,e,n){var o,i,r,s,a,l,c;!function(t,e){for(var n=t.lastElementChild;n&&(n===I.ghost||"none"===E(n,"display")||e&&!q(n,e));)n=n.previousElementSibling;return n}(this.el)?(this.el.appendChild(x),k.to={sortable:this,group:this.el,node:x,rect:y(x),offset:v(x)},this._dispatchEvent("onChange",h(h({},k),{},{event:e,originalEvent:n}))):(o=(t=w(T,t)).el,l=t.rect,t=t.offset,!o||!x||o&&o.animated||o!==x&&(O=o,k.to={sortable:this,group:this.el,node:O,rect:l,offset:t},i=e.clientX,r=e.clientY,c=l.left,s=l.right,a=l.top,l=l.bottom,c<i&&i<s&&a<r&&r<l&&(T!==this.el?(P?this.el.insertBefore(x,P):this.el.appendChild(x),this._dispatchEvent("onChange",h(h({},k),{},{event:e,originalEvent:n}))):(this._captureAnimationState(x,O),this._dispatchEvent("onChange",h(h({},k),{},{event:e,originalEvent:n})),(c=v(x)).top<t.top||c.left<t.left?this.el.insertBefore(x,o.nextElementSibling):this.el.insertBefore(x,o),this._rangeAnimate()))))},5),_onDrop:function(t){var e,n;this._unbindDragEvents(),this._unbindMoveEvents(),this._unbindDropEvents(),this._preventEvent(t),this.dragStartTimer&&clearTimeout(this.dragStartTimer),x&&(this.nativeDraggable&&m(x,"dragend",this),e=p(t).touch,D(x,this.options.chosenClass,!1),this.nativeDraggable&&(x.draggable=!1),e&&(x.style["touch-action"]=""),x.style["will-change"]="",j.sortableDown&&j.sortableMove&&(k.to.offset=v(x),k.to.rect=y(x),e=k.from.offset,n=k.to.offset,e=e.top!==n.top||e.left!==n.left,this._dispatchEvent("onDrop",{changed:e,event:t,originalEvent:t}))),c&&E(document.body,"user-select",""),this.ghost.destroy(k.to.rect),this._clearState()},_preventEvent:function(t){this.options.stopPropagation&&t.stopPropagation&&t.stopPropagation(),void 0!==t.preventDefault&&t.cancelable&&t.preventDefault()},_dispatchEvent:function(t,e){t=this.options[t];"function"==typeof t&&t(e)},_clearState:function(){j=new U,k.destroy(),x=O=P=C=M=null,A=L={x:0,y:0}},_unbindDragEvents:function(){this.nativeDraggable&&(m(this.el,"dragstart",this._onDragStart),m(this.el,"dragover",this._onDragOver),m(this.el,"dragend",this._onDrop),m(document,"drop",this))},_unbindMoveEvents:function(){m(this.ownerDocument,"pointermove",this._onMove),m(this.ownerDocument,"touchmove",this._onMove),m(this.ownerDocument,"mousemove",this._onMove),m(this.ownerDocument,"touchmove",S),m(this.ownerDocument,"mousemove",S),m(this.ownerDocument,"dragover",S)},_unbindDropEvents:function(){m(this.ownerDocument,"pointerup",this._onDrop),m(this.ownerDocument,"pointercancel",this._onDrop),m(this.ownerDocument,"touchend",this._onDrop),m(this.ownerDocument,"touchcancel",this._onDrop),m(this.ownerDocument,"mouseup",this._onDrop)}}).utils={getRect:y,getOffset:v,debounce:z,throttle:V},I}); |
{ | ||
"name": "sortable-dnd", | ||
"version": "0.2.7", | ||
"description": "JS Library for Drag and Drop, supports Sortable and Draggable", | ||
"main": "dist/sortable.js", | ||
"version": "0.3.0", | ||
"description": "JS library for drag-and-drop lists, supports sortable and draggable", | ||
"main": "dist/sortable.min.js", | ||
"files": [ | ||
@@ -29,3 +29,3 @@ "src", | ||
"author": "mfuu", | ||
"license": "ISC", | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -32,0 +32,0 @@ "url": "https://github.com/mfuu/sortable-dnd/issues" |
@@ -48,13 +48,13 @@ <p> | ||
// draggable: '#drag' // use id | ||
// dragging: (e) => e.target.parentNode // set dragging HTMLElement | ||
onDrag: (dragEl, event, originalEvent) => { | ||
// draggable: (e) => e.target.parentNode // use fundtion to set drag Element | ||
onDrag: ({ dragEl, event, originalEvent }) => { | ||
// code | ||
}, | ||
onMove: (from, ghostEl, event, originalEvent) => { | ||
onMove: ({ from, ghostEl, event, originalEvent }) => { | ||
// code | ||
}, | ||
onDrop: (changed, /* originalEvent */event) => { | ||
onDrop: ({ changed, event, originalEvent }) => { | ||
// code | ||
}, | ||
onChange: (from, to, event, originalEvent) => { | ||
onChange: ({ from, to, event, originalEvent }) => { | ||
// code | ||
@@ -79,4 +79,4 @@ } | ||
|-------------------|-------------------|-------------|--------------| | ||
| `animation` | `Number` | `150` | Animation speed moving items when sorting | | ||
| `draggable` | `String/Function` | `undefined` | Specifies which items inside the element should be draggable, the function type must return a boolean | | ||
| `draggable` | `String/Function` | `undefined` | Specifies which items inside the element should be draggable | | ||
| `group` | `String/Object` | `-` | string: 'name' or object: `{ name: 'group', put: true/false, pull: true/false }` | | ||
| `onDrag` | `Function` | `undefined` | The callback function when the drag is started | | ||
@@ -86,5 +86,4 @@ | `onMove` | `Function` | `undefined` | The callback function when the dragged element is moving | | ||
| `onChange` | `Function` | `undefined` | The callback function when the dragged element changes position | | ||
| `autoScroll` | `Boolean` | `true` | Automatic scrolling when moving to the edge of the container, **for browsers that do not support HTML5 drag events** | | ||
| `scrollStep` | `Number` | `5` | The distance to scroll each frame when autoscrolling | | ||
| `scrollThreshold` | `Number` | `15` | Threshold to trigger autoscroll | | ||
| `animation` | `Number` | `150` | Animation speed moving items when sorting | | ||
| `disabled` | `Boolean` | `false` | Disables the sortable if set to true | | ||
@@ -96,12 +95,15 @@ | ||
|-------------------|-------------------|-------------|--------------| | ||
| `disabled` | `Boolean` | `false` | Disables the sortable if set to true | | ||
| `dragging` | `Function` | `undefined` | Specifies the element witch you want to drag | | ||
| `autoScroll` | `Boolean` | `true` | Automatic scrolling when moving to the edge of the container, **for browsers that do not support HTML5 drag events** | | ||
| `scrollStep` | `Number` | `5` | The distance to scroll each frame when autoscrolling | | ||
| `scrollThreshold` | `Number` | `15` | Threshold to trigger autoscroll | | ||
| `delay` | `Number` | `0` | time in milliseconds to define when the sorting should start | | ||
| `delayOnTouchOnly`| `Boolean` | `false` | only delay if user is using touch | | ||
| `ghostAnimation` | `Number` | `0` | Ghost element animation delay before destroyed | | ||
| `chosenClass` | `String` | `{}` | The class of the selected element when dragging | | ||
| `ghostStyle` | `Object` | `{}` | The style of the mask element when dragging | | ||
| `ghostClass` | `String` | `''` | The class of the mask element when dragging | | ||
| `chosenClass` | `String` | `{}` | The class of the selected element when dragging | | ||
| `forceFallback` | `Boolean` | `false` | true: ignore the HTML5 DnD behaviour and force the fallback to kick in | | ||
| `stopPropagation` | `Boolean` | `false` | The `stopPropagation()` method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases | | ||
# LICENSE | ||
[MIT](https://github.com/mfuu/sortable-dnd/blob/main/LICENSE) |
@@ -15,5 +15,5 @@ import { getRect, setTransition, setTransform } from './utils.js' | ||
captureAnimationState() { | ||
const children = [...Array.from(this.rootEl.children)] | ||
const { start, end } = getRange(children, this.dragEl, this.dropEl) | ||
_captureAnimationState(dragEl, dropEl) { | ||
const children = [...Array.from(this.el.children)] | ||
const { start, end } = getRange(children, dragEl, dropEl) | ||
@@ -30,10 +30,10 @@ animationState.length = 0 // reset | ||
animateRange() { | ||
_rangeAnimate() { | ||
animationState.forEach(state => { | ||
const { target, rect } = state | ||
this.animate(target, rect, this.options.animation) | ||
this._animate(target, rect, this.options.animation) | ||
}) | ||
}, | ||
animate(el, preRect, animation = 150) { | ||
_animate(el, preRect, animation = 150) { | ||
const curRect = getRect(el) | ||
@@ -46,3 +46,3 @@ const left = preRect.left - curRect.left | ||
el.offsetLeft // trigger repaint | ||
el.offsetWidth // trigger repaint | ||
@@ -49,0 +49,0 @@ setTransition(el, `${animation}ms`) |
@@ -10,14 +10,15 @@ import { throttle, getRect } from './utils.js' | ||
return { | ||
_autoScroll: throttle(function(_this) { | ||
_autoScroll: throttle(function(Sortable, state) { | ||
if (!Sortable.scrollEl) return | ||
// check if is moving now | ||
if (!(_this.state.sortableDown && _this.state.sortableMove)) return | ||
const { clientX, clientY } = _this.state.sortableMove | ||
if (!(state.sortableDown && state.sortableMove)) return | ||
const { clientX, clientY } = state.sortableMove | ||
if (clientX === void 0 || clientY === void 0) return | ||
if (_this.scrollEl === _this.ownerDocument) { | ||
if (Sortable.scrollEl === Sortable.ownerDocument) { | ||
// does not support now | ||
} else { | ||
const { scrollTop, scrollLeft, scrollHeight, scrollWidth } = _this.scrollEl | ||
const { top, right, bottom, left, height, width } = getRect(_this.scrollEl) | ||
const { scrollStep, scrollThreshold } = _this.options | ||
const { scrollTop, scrollLeft, scrollHeight, scrollWidth } = Sortable.scrollEl | ||
const { top, right, bottom, left, height, width } = getRect(Sortable.scrollEl) | ||
const { scrollStep, scrollThreshold } = Sortable.options | ||
// check direction | ||
@@ -67,4 +68,4 @@ const totop = scrollTop > 0 && clientY >= top && clientY <= (top + scrollThreshold) | ||
requestAnimationFrame(() => { | ||
_this.scrollEl.scrollTo(position.x, position.y) | ||
_this._autoScroll(_this) | ||
Sortable.scrollEl.scrollTo(position.x, position.y) | ||
Sortable._autoScroll(Sortable, state) | ||
}) | ||
@@ -71,0 +72,0 @@ } |
import { css, getRect, toggleClass, setTransition, setTransform } from './utils.js' | ||
import { IOS } from './Brower.js' | ||
/** | ||
* Sortable states | ||
*/ | ||
export class State { | ||
@@ -13,18 +15,12 @@ constructor() { | ||
/** | ||
* 拖拽前后差异初始化 | ||
* Difference before and after dragging | ||
*/ | ||
export class Differ { | ||
constructor() { | ||
this.from = { node: null, rect: {}, offset: {} } | ||
this.to = { node: null, rect: {}, offset: {} } | ||
this.from = { sortable: null, group: null, node: null, rect: {}, offset: {} } | ||
this.to = { sortable: null, group: null, node: null, rect: {}, offset: {} } | ||
} | ||
get(key) { | ||
return this[key] | ||
} | ||
set(key, value) { | ||
this[key] = value | ||
} | ||
destroy() { | ||
this.from = { node: null, rect: {}, offset: {} } | ||
this.to = { node: null, rect: {}, offset: {} } | ||
this.from = { sortable: null, group: null, node: null, rect: {}, offset: {} } | ||
this.to = { sortable: null, group: null, node: null, rect: {}, offset: {} } | ||
} | ||
@@ -34,7 +30,7 @@ } | ||
/** | ||
* 拖拽中的元素 | ||
* Elements being dragged | ||
*/ | ||
export class Ghost { | ||
constructor(sortable) { | ||
this.$el = null | ||
this.el = null | ||
this.distance = { x: 0, y: 0 } | ||
@@ -46,27 +42,29 @@ this.options = sortable.options | ||
init(el, rect, append = true) { | ||
this.$el = el | ||
this.el = el | ||
if (!append) return | ||
const { ghostClass, ghostStyle = {} } = this.options | ||
toggleClass(this.$el, ghostClass, true) | ||
toggleClass(this.el, ghostClass, true) | ||
css(this.$el, 'box-sizing', 'border-box') | ||
css(this.$el, 'margin', 0) | ||
css(this.$el, 'top', rect.top) | ||
css(this.$el, 'left', rect.left) | ||
css(this.$el, 'width', rect.width) | ||
css(this.$el, 'height', rect.height) | ||
css(this.$el, 'opacity', '0.8') | ||
// css(this.$el, 'position', IOS ? 'absolute' : 'fixed') | ||
css(this.$el, 'position', 'fixed') | ||
css(this.$el, 'zIndex', '100000') | ||
css(this.$el, 'pointerEvents', 'none') | ||
css(this.el, 'box-sizing', 'border-box') | ||
css(this.el, 'margin', 0) | ||
css(this.el, 'top', rect.top) | ||
css(this.el, 'left', rect.left) | ||
css(this.el, 'width', rect.width) | ||
css(this.el, 'height', rect.height) | ||
css(this.el, 'opacity', '0.8') | ||
// css(this.el, 'position', IOS ? 'absolute' : 'fixed') | ||
css(this.el, 'position', 'fixed') | ||
css(this.el, 'zIndex', '100000') | ||
css(this.el, 'pointerEvents', 'none') | ||
this.setStyle(ghostStyle) | ||
setTransition(this.$el, 'none') | ||
setTransform(this.$el, 'translate3d(0px, 0px, 0px)') | ||
setTransition(this.el, 'none') | ||
setTransform(this.el, 'translate3d(0px, 0px, 0px)') | ||
if (append) this.container.appendChild(this.$el) | ||
this.container.appendChild(this.el) | ||
css(this.$el, 'transform-origin', (this.distance.x / parseInt(this.$el.style.width) * 100) + '% ' + (this.distance.y / parseInt(this.$el.style.height) * 100) + '%') | ||
css(this.el, 'transform-origin', (this.distance.x / parseInt(this.el.style.width) * 100) + '% ' + (this.distance.y / parseInt(this.el.style.height) * 100) + '%') | ||
css(this.el, 'transform', 'translateZ(0)') | ||
} | ||
@@ -76,3 +74,3 @@ | ||
for (const key in style) { | ||
css(this.$el, key, style[key]) | ||
css(this.el, key, style[key]) | ||
} | ||
@@ -82,15 +80,21 @@ } | ||
rect() { | ||
return getRect(this.$el) | ||
return getRect(this.el) | ||
} | ||
move(x, y, smooth = false) { | ||
if (!this.$el) return | ||
setTransition(this.$el, smooth ? `${this.options.ghostAnimation}ms` : 'none') | ||
setTransform(this.$el, `translate3d(${x}px, ${y}px, 0)`) | ||
if (!this.el) return | ||
setTransition(this.el, smooth ? `${this.options.ghostAnimation}ms` : 'none') | ||
setTransform(this.el, `translate3d(${x}px, ${y}px, 0)`) | ||
} | ||
clear() { | ||
this.distance = { x: 0, y: 0 } | ||
this.el && this.el.remove() | ||
this.el = null | ||
} | ||
destroy(rect) { | ||
if (!this.$el) return | ||
const left = parseInt(this.$el.style.left) | ||
const top = parseInt(this.$el.style.top) | ||
if (!this.el) return | ||
const left = parseInt(this.el.style.left) | ||
const top = parseInt(this.el.style.top) | ||
this.move(rect.left - left, rect.top - top, true) | ||
@@ -100,8 +104,2 @@ const { ghostAnimation } = this.options | ||
} | ||
clear() { | ||
this.$el && this.$el.remove() | ||
this.distance = { x: 0, y: 0 } | ||
this.$el = null | ||
} | ||
} |
@@ -5,2 +5,3 @@ import { | ||
css, | ||
expando, | ||
matches, | ||
@@ -11,2 +12,3 @@ getRect, | ||
debounce, | ||
lastChild, | ||
getOffset, | ||
@@ -16,2 +18,4 @@ _nextTick, | ||
toggleClass, | ||
isHTMLElement, | ||
offsetChanged, | ||
getParentAutoScrollElement | ||
@@ -23,3 +27,2 @@ } from './utils.js' | ||
import Animation from './Animation.js' | ||
import Events from './Events.js' | ||
@@ -30,3 +33,92 @@ // -------------------------------- Sortable ---------------------------------- | ||
const sortables = [] | ||
let rootEl, | ||
dragEl, | ||
dropEl, | ||
nextEl, | ||
ghostEl, | ||
activeGroup, | ||
move = { x: 0, y: 0 }, | ||
state = new State, // Status record during drag and drop | ||
differ = new Differ() // Record the difference before and after dragging | ||
const _prepareGroup = function (options) { | ||
let group = {} | ||
let originalGroup = options.group | ||
if (!originalGroup || typeof originalGroup != 'object') { | ||
originalGroup = { name: originalGroup } | ||
} | ||
group.name = originalGroup.name | ||
group.pull = originalGroup.pull | ||
group.put = originalGroup.put | ||
options.group = group | ||
} | ||
/** | ||
* get nearest Sortable | ||
*/ | ||
const _nearestSortable = function(evt) { | ||
_checkPosition(evt) | ||
if (dragEl) { | ||
evt = evt.touches ? evt.touches[0] : evt | ||
const { clientX, clientY } = evt | ||
const nearest = _detectNearestSortable(clientX, clientY) | ||
if (nearest) { | ||
// Create imitation event | ||
let event = {} | ||
for (let i in evt) { | ||
event[i] = evt[i] | ||
} | ||
event.target = document.elementFromPoint(clientX, clientY) | ||
event.rootEl = nearest | ||
event.preventDefault = void 0 | ||
event.stopPropagation = void 0 | ||
nearest[expando]._triggerEvent(event) | ||
} | ||
} | ||
} | ||
/** | ||
* Detects first nearest empty sortable to X and Y position using emptyInsertThreshold. | ||
* @param {Number} x X position | ||
* @param {Number} y Y position | ||
* @return {HTMLElement} Element of the first found nearest Sortable | ||
*/ | ||
const _detectNearestSortable = function(x, y) { | ||
let result | ||
sortables.some((sortable) => { | ||
const threshold = sortable[expando].options.emptyInsertThreshold | ||
if (!threshold) return | ||
const rect = getRect(sortable), | ||
insideHorizontally = x >= (rect.left - threshold) && x <= (rect.right + threshold), | ||
insideVertically = y >= (rect.top - threshold) && y <= (rect.bottom + threshold) | ||
if (insideHorizontally && insideVertically) { | ||
return (result = sortable) | ||
} | ||
}) | ||
return result | ||
} | ||
let lastPosition = { x: 0, y: 0 } | ||
const _checkPosition = function(evt) { | ||
const { clientX, clientY } = evt | ||
const distanceX = clientX - lastPosition.x | ||
const distanceY = clientY - lastPosition.y | ||
lastPosition.x = clientX | ||
lastPosition.y = clientY | ||
if ((clientX !== void 0 && Math.abs(distanceX) < 1) && (clientY !== void 0 && Math.abs(distanceY) < 1)) { | ||
return | ||
} | ||
} | ||
/** | ||
* @class Sortable | ||
@@ -41,3 +133,5 @@ * @param {HTMLElement} el group element | ||
this.rootEl = el // root element | ||
el[expando] = this | ||
this.el = el | ||
this.scrollEl = getParentAutoScrollElement(el, true) // scroll element | ||
@@ -48,2 +142,11 @@ this.options = options = Object.assign({}, options) | ||
const defaults = { | ||
group: '', // string: 'group' or object: { name: 'group', put: true | false, pull: true | false } | ||
animation: 150, // Define the timing of the sorting animation | ||
draggable: undefined, // String: css selector, Function: (e) => return true | ||
onDrag: undefined, // The callback function triggered when dragging starts: () => {} | ||
onMove: undefined, // The callback function during drag and drop: (from, to) => {} | ||
onDrop: undefined, // The callback function when the drag is completed: (from, to, changed) => {} | ||
onChange: undefined, // The callback function when dragging an element to change its position: (from, to) => {} | ||
autoScroll: true, // Auto scrolling when dragging to the edge of the container | ||
@@ -56,3 +159,2 @@ scrollStep: 5, // The distance to scroll each frame | ||
disabled: false, // Defines whether the sortable object is available or not. When it is true, the sortable object cannot drag and drop sorting and other functions. When it is false, it can be sorted, which is equivalent to a switch. | ||
animation: 150, // Define the timing of the sorting animation | ||
@@ -63,9 +165,2 @@ ghostAnimation: 0, // Animation when the ghost element is destroyed | ||
chosenClass: '', // Chosen element style | ||
draggable: undefined, // String: css selector, Function: (e) => return true | ||
dragging: undefined, // Set the drag element, must be a function and must return an HTMLElement: (e) => return e.target | ||
onDrag: undefined, // The callback function triggered when dragging starts: () => {} | ||
onMove: undefined, // The callback function during drag and drop: (from, to) => {} | ||
onDrop: undefined, // The callback function when the drag is completed: (from, to, changed) => {} | ||
onChange: undefined, // The callback function when dragging an element to change its position: (from, to) => {} | ||
@@ -78,2 +173,3 @@ fallbackOnBody: false, | ||
supportTouch: 'ontouchstart' in window, | ||
emptyInsertThreshold: 5 | ||
} | ||
@@ -86,21 +182,35 @@ | ||
this.container = this.options.fallbackOnBody ? document.body : this.rootEl | ||
this.container = this.options.fallbackOnBody ? document.body : el | ||
this.nativeDraggable = this.options.forceFallback ? false : supportDraggable | ||
this.move = { x: 0, y: 0 } | ||
this.state = new State // Status record during drag and drop | ||
this.differ = new Differ() // Record the difference before and after dragging | ||
this.ghost = new Ghost(this) // Mask element while dragging | ||
this.dragEl = null // Drag element | ||
this.dropEl = null // Drop element | ||
this.dragStartTimer = null // setTimeout timer | ||
this.autoScrollTimer = null | ||
Object.assign( | ||
this, | ||
Events(), | ||
Animation(), | ||
AutoScroll(), | ||
) | ||
this._bindEventListener() | ||
_prepareGroup(options) | ||
// Bind all private methods | ||
for (let fn in this) { | ||
if (fn.charAt(0) === '_' && typeof this[fn] === 'function') { | ||
this[fn] = this[fn].bind(this) | ||
} | ||
} | ||
const { supportPointer, supportTouch } = this.options | ||
if (supportPointer) { | ||
on(el, 'pointerdown', this._onDrag) | ||
} else if (supportTouch) { | ||
on(el, 'touchstart', this._onDrag) | ||
} else { | ||
on(el, 'mousedown', this._onDrag) | ||
} | ||
if (this.nativeDraggable) { | ||
on(el, 'dragover', this) | ||
on(el, 'dragenter', this) | ||
} | ||
sortables.push(el) | ||
Object.assign(this, Animation(), AutoScroll()) | ||
} | ||
@@ -111,2 +221,3 @@ | ||
// -------------------------------- public methods ---------------------------------- | ||
/** | ||
@@ -116,6 +227,16 @@ * Destroy | ||
destroy: function() { | ||
this.el[expando] = null | ||
off(this.el, 'pointerdown', this._onDrag) | ||
off(this.el, 'touchstart', this._onDrag) | ||
off(this.el, 'mousedown', this._onDrag) | ||
if (this.nativeDraggable) { | ||
off(this.el, 'dragover', this) | ||
off(this.el, 'dragenter', this) | ||
} | ||
this._clearState() | ||
this._clearEvent() | ||
// Remove draggable attributes | ||
Array.prototype.forEach.call(this.rootEl.querySelectorAll('[draggable]'), function (el) { | ||
Array.prototype.forEach.call(this.el.querySelectorAll('[draggable]'), function (el) { | ||
el.removeAttribute('draggable') | ||
@@ -141,3 +262,3 @@ }) | ||
_onDrag: function(/** Event|TouchEvent */evt) { | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0 || this.options.disabled) return // only left button and enabled | ||
if (/mousedown|pointerdown/.test(evt.type) && evt.button !== 0 || this.options.disabled || !this.options.group.pull) return // only left button and enabled | ||
@@ -148,15 +269,16 @@ const { touch, e, target } = getEvent(evt) | ||
if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') return | ||
if (target === this.rootEl) return true | ||
if (target === this.el) return true | ||
if (this.options.stopPropagation) evt.stopPropagation() | ||
if (this.options.stopPropagation) evt.stopPropagation && evt.stopPropagation() // prevent events from bubbling | ||
const { draggable, dragging } = this.options | ||
const { draggable } = this.options | ||
if (typeof draggable === 'function') { | ||
if (!draggable(e)) return true | ||
// Function type must return a HTMLElement if used to specifies the drag el | ||
const value = draggable(e) | ||
if (!value) return true | ||
if (isHTMLElement(value)) dragEl = value // set drag element | ||
} else if (typeof draggable === 'string') { | ||
// String use as 'tag' or '.class' or '#id' | ||
if (!matches(target, draggable)) return true | ||
} else if (draggable !== undefined) { | ||
} else if (draggable) { | ||
throw new Error(`draggable expected "function" or "string" but received "${typeof draggable}"`) | ||
@@ -166,22 +288,20 @@ } | ||
// Get the dragged element | ||
if (dragging) { | ||
if (typeof dragging === 'function') this.dragEl = dragging(e) | ||
else throw new Error(`dragging expected "function" or "string" but received "${typeof dragging}"`) | ||
} else { | ||
this.dragEl = getElement(this.rootEl, target, true) | ||
} | ||
if (!dragEl) dragEl = getElement(this.el, target, true) | ||
// No dragging is allowed when there is no dragging element | ||
if (!this.dragEl || this.dragEl.animated) return true | ||
if (!dragEl || dragEl.animated) return true | ||
// solve the problem that the mobile cannot be dragged | ||
if (touch) this.dragEl.style['touch-action'] = 'none' | ||
if (touch) dragEl.style['touch-action'] = 'none' | ||
// get the position of the dragged element in the list | ||
const { rect, offset } = getElement(this.rootEl, this.dragEl) | ||
this.move = { x: e.clientX, y: e.clientY } | ||
this.differ.from = { node: this.dragEl, rect, offset} | ||
const { rect, offset } = getElement(this.el, dragEl) | ||
move = { x: e.clientX, y: e.clientY } | ||
differ.from = { sortable: this, group: this.el, node: dragEl, rect, offset} | ||
this.ghost.distance = { x: e.clientX - rect.left, y: e.clientY - rect.top } | ||
this.state.sortableDown = e // sortable state down is active | ||
state.sortableDown = e // sortable state down is active | ||
on(this.ownerDocument, 'dragover', _nearestSortable) | ||
on(this.ownerDocument, 'mousemove', _nearestSortable) | ||
on(this.ownerDocument, 'touchmove', _nearestSortable) | ||
// Solve the problem that `dragend` does not take effect when the `dragover` event is not triggered | ||
@@ -201,5 +321,18 @@ on(this.ownerDocument, 'pointerup', this._onDrop) | ||
}, | ||
_onStart: function(/** Event|TouchEvent */e, touch) { | ||
rootEl = this.el | ||
nextEl = dragEl.nextSibling | ||
activeGroup = this.options.group | ||
if (!this.nativeDraggable || touch) { | ||
this._bindMoveEvents(touch) | ||
if (this.options.supportPointer) { | ||
on(this.ownerDocument, 'pointermove', this._onMove) | ||
} else if (touch) { | ||
on(this.ownerDocument, 'touchmove', this._onMove) | ||
} else { | ||
on(this.ownerDocument, 'mousemove', this._onMove) | ||
} | ||
on(this.ownerDocument, 'pointercancel', this._onDrop) | ||
@@ -209,7 +342,6 @@ on(this.ownerDocument, 'touchcancel', this._onDrop) | ||
// allow HTML5 drag event | ||
this.dragEl.draggable = true | ||
dragEl.draggable = true | ||
this._onDragStart = this._onDragStart.bind(this) | ||
this._onDragOver = this._onDragOver.bind(this) | ||
on(this.rootEl, 'dragstart', this._onDragStart) | ||
on(dragEl, 'dragend', this) | ||
on(this.el, 'dragstart', this._onDragStart) | ||
} | ||
@@ -230,38 +362,77 @@ | ||
// -------------------------------- trigger ---------------------------------- | ||
_triggerEvent(evt) { | ||
if (activeGroup.name !== this.options.group.name) return | ||
rootEl = evt.rootEl | ||
if (this.nativeDraggable) { | ||
on(this.el, 'dragend', this._onDrop) | ||
this._onDragOver(evt) | ||
} else { | ||
this._onMove(evt) | ||
} | ||
}, | ||
// -------------------------------- drag event ---------------------------------- | ||
_onDragStart: function(evt) { | ||
// elements can only be dragged after firefox sets setData | ||
evt.dataTransfer.setData('te', evt.target.innerText) | ||
if (evt.dataTransfer) { | ||
evt.dataTransfer.setData('draggableEffect', evt.target.innerText) | ||
evt.dataTransfer.effectAllowed = 'move' | ||
} | ||
on(this.rootEl, 'dragover', this._onDragOver) | ||
on(this.rootEl, 'dragend', this._onDrop) | ||
on(this.el, 'dragover', this._onDragOver) | ||
on(this.el, 'dragend', this._onDrop) | ||
}, | ||
_onDragOver: function(evt) { | ||
if (!this.state.sortableDown) return | ||
const { stopPropagation } = this.options | ||
stopPropagation && evt.stopPropagation && evt.stopPropagation() // prevent events from bubbling | ||
evt.preventDefault !== void 0 && evt.cancelable && evt.preventDefault() // prevent scrolling | ||
if (evt.dataTransfer) evt.dataTransfer.dropEffect = 'move' | ||
if (!state.sortableDown || !dragEl) return | ||
this._preventEvent(evt) | ||
_checkPosition(evt) | ||
const { clientX, clientY } = evt | ||
const distanceX = clientX - this.move.x | ||
const distanceY = clientY - this.move.y | ||
if ((clientX !== void 0 && Math.abs(distanceX) <= 0) && (clientY !== void 0 && Math.abs(distanceY) <= 0)) { | ||
return | ||
} | ||
// truly started | ||
this._onStarted(evt, evt) | ||
if (evt.target === this.rootEl) return | ||
this._onChange(this, evt.target, evt, evt) | ||
// onMove callback | ||
this._dispatchEvent('onMove', { ...differ, ghostEl, event: evt, originalEvent: evt }) | ||
if (this.options.group.put || differ.from.group === this.el) this._onChange(evt.target, evt, evt) | ||
}, | ||
// -------------------------------- real started ---------------------------------- | ||
_onStarted: function(e, /** originalEvent */evt) { | ||
state.sortableMove = e // sortable state move is active | ||
if (!ghostEl) { | ||
// onDrag callback | ||
this._dispatchEvent('onDrag', { dragEl, event: e, originalEvent: evt }) | ||
// Init in the move event to prevent conflict with the click event | ||
const { rect } = differ.from | ||
ghostEl = dragEl.cloneNode(true) | ||
this.ghost.init(ghostEl, rect, !this.nativeDraggable) | ||
Sortable.ghost = ghostEl | ||
// add class for drag element | ||
toggleClass(dragEl, this.options.chosenClass, true) | ||
dragEl.style['will-change'] = 'transform' | ||
if (this.nativeDraggable) { | ||
this._unbindDropEvents() | ||
on(document, 'drop', this) | ||
} | ||
if (Safari) css(document.body, 'user-select', 'none') | ||
} | ||
}, | ||
// -------------------------------- on move ---------------------------------- | ||
_onMove: function(/** Event|TouchEvent */evt) { | ||
if (!this.state.sortableDown) return | ||
if (!state.sortableDown || !dragEl) return | ||
const { touch, e, target } = getEvent(evt) | ||
const { clientX, clientY } = e | ||
const distanceX = clientX - this.move.x | ||
const distanceY = clientY - this.move.y | ||
const distanceX = clientX - move.x | ||
const distanceY = clientY - move.y | ||
@@ -272,5 +443,3 @@ if ((clientX !== void 0 && Math.abs(distanceX) <= 0) && (clientY !== void 0 && Math.abs(distanceY) <= 0)) { | ||
const { stopPropagation } = this.options | ||
stopPropagation && evt.stopPropagation && evt.stopPropagation() // prevent events from bubbling | ||
evt.preventDefault !== void 0 && evt.cancelable && evt.preventDefault() // prevent scrolling | ||
this._preventEvent(evt) | ||
@@ -281,70 +450,63 @@ this._onStarted(e, evt) | ||
// onMove callback | ||
const { onMove } = this.options | ||
if (onMove && typeof onMove === 'function') onMove(this.differ.from, this.ghost.$el, e, evt) | ||
this._dispatchEvent('onMove', { ...differ, ghostEl, event: e, originalEvent: evt }) | ||
// boundary value judgment | ||
if (clientX < 0 || clientY < 0) return | ||
const { top, right, bottom, left } = getRect(this.rootEl) | ||
if (clientX < left || clientX > right || clientY < top || clientY > bottom) return | ||
// check if element will exchange | ||
this._onChange(this, target, e, evt) | ||
this._onChange(target, e, evt) | ||
// auto scroll | ||
this.autoScrollTimer && clearTimeout(this.autoScrollTimer) | ||
clearTimeout(this.autoScrollTimer) | ||
if (this.options.autoScroll) { | ||
this.autoScrollTimer = setTimeout(() => this._autoScroll(this), 0) | ||
this.autoScrollTimer = setTimeout(() => this._autoScroll(this, state), 0) | ||
} | ||
}, | ||
_onStarted: function(e, /** originalEvent */evt) { | ||
this.state.sortableMove = e // sortable state move is active | ||
if (!this.ghost.$el) { | ||
// onDrag callback | ||
const { onDrag } = this.options | ||
if (onDrag && typeof onDrag === 'function') onDrag(this.dragEl, e, evt) | ||
// Init in the move event to prevent conflict with the click event | ||
const { rect } = this.differ.from | ||
const ghostEl = this.dragEl.cloneNode(true) | ||
this.ghost.init(ghostEl, rect, !this.nativeDraggable) | ||
// -------------------------------- on change ---------------------------------- | ||
_onChange: debounce(function(target, e, evt) { | ||
if (!lastChild(this.el)) { | ||
this.el.appendChild(dragEl) | ||
// add class for drag element | ||
toggleClass(this.dragEl, this.options.chosenClass, true) | ||
this.dragEl.style['will-change'] = 'transform' | ||
differ.to = { sortable: this, group: this.el, node: dragEl, rect: getRect(dragEl), offset: getOffset(dragEl) } | ||
// onChange callback | ||
this._dispatchEvent('onChange', { ...differ, event: e, originalEvent: evt }) | ||
} else { | ||
const { el, rect, offset } = getElement(rootEl, target) | ||
if (!el || !dragEl || (el && el.animated)) return | ||
if (el === dragEl) return | ||
if (Safari) css(document.body, 'user-select', 'none') | ||
if (this.nativeDraggable) this._unbindDropEvents() | ||
} | ||
}, | ||
_onChange: debounce(function(_this, target, e, evt) { | ||
const { el, rect, offset } = getElement(_this.rootEl, target) | ||
if (!el || (el && el.animated)) return | ||
_this.dropEl = el | ||
const { clientX, clientY } = e | ||
const { left, right, top, bottom } = rect | ||
dropEl = el | ||
differ.to = { sortable: this, group: this.el, node: dropEl, rect, offset } | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
const { clientX, clientY } = e | ||
const { left, right, top, bottom } = rect | ||
// swap when the elements before and after the drag are inconsistent | ||
if (el !== _this.dragEl) { | ||
_this.differ.to = { node: _this.dropEl, rect, offset } | ||
if (clientX > left && clientX < right && clientY > top && clientY < bottom) { | ||
if (rootEl !== this.el) { | ||
if (nextEl) { | ||
this.el.insertBefore(dragEl, nextEl) | ||
} else { | ||
this.el.appendChild(dragEl) | ||
} | ||
_this.captureAnimationState() | ||
// onChange callback | ||
this._dispatchEvent('onChange', { ...differ, event: e, originalEvent: evt }) | ||
} else { | ||
this._captureAnimationState(dragEl, dropEl) | ||
const { onChange } = _this.options | ||
const _offset = getOffset(_this.dragEl) | ||
// onChange callback | ||
this._dispatchEvent('onChange', { ...differ, event: e, originalEvent: evt }) | ||
// the top value is compared first, and the left is compared if the top value is the same | ||
const _offset = getOffset(dragEl) | ||
if (_offset.top < offset.top || _offset.left < offset.left) { | ||
this.el.insertBefore(dragEl, el.nextElementSibling) | ||
} else { | ||
this.el.insertBefore(dragEl, el) | ||
} | ||
// onChange callback | ||
if (onChange && typeof onChange === 'function') onChange(_this.differ.from, _this.differ.to, e, evt) | ||
// the top value is compared first, and the left is compared if the top value is the same | ||
if (_offset.top < offset.top || _offset.left < offset.left) { | ||
_this.rootEl.insertBefore(_this.dragEl, el.nextElementSibling) | ||
} else { | ||
_this.rootEl.insertBefore(_this.dragEl, el) | ||
this._rangeAnimate() | ||
} | ||
_this.animateRange() | ||
} | ||
} | ||
}, 5), | ||
@@ -357,38 +519,81 @@ | ||
this._unbindDropEvents() | ||
this._preventEvent(evt) | ||
this.dragStartTimer && clearTimeout(this.dragStartTimer) | ||
const { stopPropagation } = this.options | ||
stopPropagation && evt.stopPropagation() | ||
evt.preventDefault && evt.preventDefault() | ||
if (dragEl) { | ||
if (this.nativeDraggable) off(dragEl, 'dragend', this) | ||
const { touch } = getEvent(evt) | ||
// clear style and class | ||
toggleClass(this.dragEl, this.options.chosenClass, false) | ||
if (this.nativeDraggable) this.dragEl.draggable = false | ||
if (touch) this.dragEl.style['touch-action'] = '' | ||
this.dragEl.style['will-change'] = '' | ||
const { touch } = getEvent(evt) | ||
// clear style, attrs and class | ||
toggleClass(dragEl, this.options.chosenClass, false) | ||
if (this.nativeDraggable) dragEl.draggable = false | ||
if (touch) dragEl.style['touch-action'] = '' | ||
dragEl.style['will-change'] = '' | ||
if (this.state.sortableDown && this.state.sortableMove) { | ||
// re-acquire the offset and rect values of the dragged element as the value after the drag is completed | ||
this.differ.to.offset = getOffset(this.dragEl) | ||
this.differ.to.rect = getRect(this.dragEl) | ||
if (state.sortableDown && state.sortableMove) { | ||
// re-acquire the offset and rect values of the dragged element as the value after the drag is completed | ||
differ.to.offset = getOffset(dragEl) | ||
differ.to.rect = getRect(dragEl) | ||
const changed = offsetChanged(differ.from.offset, differ.to.offset) | ||
this._dispatchEvent('onDrop', { changed, event: evt, originalEvent: evt }) | ||
} | ||
} | ||
const { from, to } = this.differ | ||
// compare whether the element is swapped by offset | ||
const changed = from.offset.top !== to.offset.top || from.offset.left !== to.offset.left | ||
// onDrop callback | ||
const { onDrop } = this.options | ||
if (onDrop && typeof onDrop === 'function') onDrop(changed, evt) | ||
} | ||
if (Safari) css(document.body, 'user-select', '') | ||
this.ghost.destroy(this.differ.to.rect) | ||
this.state = new State | ||
this.ghost.destroy(differ.to.rect) | ||
this._clearState() | ||
}, | ||
// -------------------------------- event ---------------------------------- | ||
_preventEvent: function(evt) { | ||
if (this.options.stopPropagation) evt.stopPropagation && evt.stopPropagation() // prevent events from bubbling | ||
evt.preventDefault !== void 0 && evt.cancelable && evt.preventDefault() | ||
}, | ||
_dispatchEvent: function(event, params) { | ||
const callback = this.options[event] | ||
if (typeof callback === 'function') callback(params) | ||
}, | ||
// -------------------------------- clear ---------------------------------- | ||
_clearState: function() { | ||
this.state = new State | ||
this.differ.destroy() | ||
this.dragEl = null | ||
this.dropEl = null | ||
state = new State | ||
differ.destroy() | ||
dragEl = | ||
dropEl = | ||
nextEl = | ||
ghostEl = | ||
activeGroup = null | ||
move = | ||
lastPosition = { x: 0, y: 0 } | ||
}, | ||
_unbindDragEvents: function() { | ||
if (this.nativeDraggable) { | ||
off(this.el, 'dragstart', this._onDragStart) | ||
off(this.el, 'dragover', this._onDragOver) | ||
off(this.el, 'dragend', this._onDrop) | ||
off(document, 'drop', this) | ||
} | ||
}, | ||
_unbindMoveEvents: function() { | ||
off(this.ownerDocument, 'pointermove', this._onMove) | ||
off(this.ownerDocument, 'touchmove', this._onMove) | ||
off(this.ownerDocument, 'mousemove', this._onMove) | ||
off(this.ownerDocument, 'touchmove', _nearestSortable) | ||
off(this.ownerDocument, 'mousemove', _nearestSortable) | ||
off(this.ownerDocument, 'dragover', _nearestSortable) | ||
}, | ||
_unbindDropEvents: function() { | ||
off(this.ownerDocument, 'pointerup', this._onDrop) | ||
off(this.ownerDocument, 'pointercancel', this._onDrop) | ||
off(this.ownerDocument, 'touchend', this._onDrop) | ||
off(this.ownerDocument, 'touchcancel', this._onDrop) | ||
off(this.ownerDocument, 'mouseup', this._onDrop) | ||
} | ||
@@ -402,5 +607,4 @@ } | ||
throttle, | ||
getParentAutoScrollElement | ||
} | ||
export default Sortable |
import { IE11OrLess } from './Brower.js' | ||
import Sortable from './Sortable.js' | ||
@@ -15,2 +16,16 @@ const captureMode = { | ||
/** | ||
* check if is HTMLElement | ||
*/ | ||
export function isHTMLElement(obj) { | ||
let d = document.createElement("div") | ||
try { | ||
d.appendChild(obj.cloneNode(true)) | ||
return obj.nodeType == 1 ? true : false | ||
} catch(e) { | ||
return obj == window || obj == document | ||
} | ||
} | ||
/** | ||
* set transition style | ||
@@ -266,2 +281,25 @@ * @param {HTMLElement} el | ||
/** | ||
* Gets the last child in the el, ignoring ghostEl or invisible elements (clones) | ||
* @param {HTMLElement} el Parent element | ||
* @param {selector} selector Any other elements that should be ignored | ||
* @return {HTMLElement} The last child, ignoring ghostEl | ||
*/ | ||
export function lastChild(el, selector) { | ||
let last = el.lastElementChild | ||
while ( | ||
last && | ||
( | ||
last === Sortable.ghost || | ||
css(last, 'display') === 'none' || | ||
selector && !matches(last, selector) | ||
) | ||
) { | ||
last = last.previousElementSibling | ||
} | ||
return last || null | ||
} | ||
/** | ||
* add or remove element's class | ||
@@ -311,2 +349,9 @@ * @param {HTMLElement} el element | ||
/** | ||
* Check whether the front and rear positions are consistent | ||
*/ | ||
export function offsetChanged(o1, o2) { | ||
return o1.top !== o2.top || o1.left !== o2.left | ||
} | ||
export function css(el, prop, val) { | ||
@@ -360,20 +405,2 @@ let style = el && el.style | ||
export default { | ||
on, | ||
off, | ||
css, | ||
getRect, | ||
matches, | ||
throttle, | ||
debounce, | ||
getIndex, | ||
_nextTick, | ||
isChildOf, | ||
getElement, | ||
toggleClass, | ||
setTransform, | ||
setTransition, | ||
supportPassive, | ||
getWindowScrollingElement, | ||
getParentAutoScrollElement, | ||
} | ||
export const expando = 'Sortable' + Date.now() |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
109278
0
2392
105
11