Browse Source

#1274: + swap option

swap
RubaXa 7 years ago
parent
commit
d776a11d59
  1. 10
      README.md
  2. 90
      Sortable.js
  3. 4
      st/app.css

10
README.md

@ -85,6 +85,7 @@ var sortable = new Sortable(el, {
touchStartThreshold: 0, // px, how many pixels the point should move before cancelling a delayed drag event touchStartThreshold: 0, // px, how many pixels the point should move before cancelling a delayed drag event
disabled: false, // Disables the sortable if set to true. disabled: false, // Disables the sortable if set to true.
store: null, // @see Store store: null, // @see Store
swap: false, // The dragged item to be swapped with the item you drop it on (instead of inserted next to it)
animation: 150, // ms, animation speed moving items when sorting, `0` — without animation animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
handle: ".my-handle", // Drag handle selector within list items handle: ".my-handle", // Drag handle selector within list items
filter: ".ignore-elements", // Selectors that do not lead to dragging (String or Function) filter: ".ignore-elements", // Selectors that do not lead to dragging (String or Function)
@ -93,6 +94,7 @@ var sortable = new Sortable(el, {
ghostClass: "sortable-ghost", // Class name for the drop placeholder ghostClass: "sortable-ghost", // Class name for the drop placeholder
chosenClass: "sortable-chosen", // Class name for the chosen item chosenClass: "sortable-chosen", // Class name for the chosen item
dragClass: "sortable-drag", // Class name for the dragging item dragClass: "sortable-drag", // Class name for the dragging item
swapClass: "sortable-swap-highlight", // Class name for the element under the dragged item.
dataIdAttr: 'data-id', dataIdAttr: 'data-id',
forceFallback: false, // ignore the HTML5 DnD behaviour and force the fallback to kick in forceFallback: false, // ignore the HTML5 DnD behaviour and force the fallback to kick in
@ -404,6 +406,14 @@ The speed at which the window should scroll once the mouse pointer gets within t
--- ---
#### `swap` option
Option to true will cause a dragged item to be swapped with the item you drop it on (instead of inserted next to it)
Demo: http://jsbin.com/covamiqufo/1/edit?html,js,output
---
### Event object ([demo](http://jsbin.com/xedusu/edit?js,output)) ### Event object ([demo](http://jsbin.com/xedusu/edit?js,output))
- to:`HTMLElement` — list, in which moved element. - to:`HTMLElement` — list, in which moved element.

90
Sortable.js

@ -139,7 +139,7 @@
if (scrollEl) { if (scrollEl) {
el = scrollEl; el = scrollEl;
rect = scrollEl.getBoundingClientRect(); rect = _getBoundingClientRect(scrollEl);
vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens); vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens); vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
} }
@ -264,13 +264,15 @@
disabled: false, disabled: false,
store: null, store: null,
handle: null, handle: null,
scroll: true, scroll: true,
scrollSensitivity: 30, scrollSensitivity: 30,
scrollSpeed: 10, scrollSpeed: 10,
swap: false,
draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*', draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
ghostClass: 'sortable-ghost', ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen', chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag', dragClass: 'sortable-drag',
swapClass: 'sortable-swap-highlight',
ignore: 'a, img', ignore: 'a, img',
filter: null, filter: null,
preventOnFilter: true, preventOnFilter: true,
@ -633,7 +635,7 @@
_appendGhost: function () { _appendGhost: function () {
if (!ghostEl) { if (!ghostEl) {
var rect = dragEl.getBoundingClientRect(), var rect = _getBoundingClientRect(dragEl),
css = _css(dragEl), css = _css(dragEl),
options = this.options, options = this.options,
ghostRect; ghostRect;
@ -653,10 +655,14 @@
_css(ghostEl, 'zIndex', '100000'); _css(ghostEl, 'zIndex', '100000');
_css(ghostEl, 'pointerEvents', 'none'); _css(ghostEl, 'pointerEvents', 'none');
options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl); if (options.fallbackOnBody) {
_insertBefore(document.body, ghostEl, null);
} else {
_insertBefore(rootEl, ghostEl, null);
}
// Fixing dimensions. // Fixing dimensions.
ghostRect = ghostEl.getBoundingClientRect(); ghostRect = _getBoundingClientRect(ghostEl);
_css(ghostEl, 'width', rect.width * 2 - ghostRect.width); _css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
_css(ghostEl, 'height', rect.height * 2 - ghostRect.height); _css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
} }
@ -680,7 +686,7 @@
// #1143: IFrame support workaround // #1143: IFrame support workaround
_this._cloneId = _nextTick(function () { _this._cloneId = _nextTick(function () {
rootEl.insertBefore(cloneEl, dragEl); _insertBefore(rootEl, cloneEl, dragEl);
_dispatchEvent(_this, rootEl, 'clone', dragEl); _dispatchEvent(_this, rootEl, 'clone', dragEl);
}); });
} }
@ -768,28 +774,36 @@
} }
target = _closest(evt.target, options.draggable, el); target = _closest(evt.target, options.draggable, el);
dragRect = dragEl.getBoundingClientRect(); dragRect = _getBoundingClientRect(dragEl);
if (putSortable !== this) { if (putSortable !== this) {
putSortable = this; putSortable = this;
isMovingBetweenSortable = true; isMovingBetweenSortable = true;
} }
if (options.swap) {
if (target) {
lastEl && _toggleClass(lastEl, options.swapClass, false);
_toggleClass(target, options.swapClass, true);
lastEl = target;
}
return;
}
if (revert) { if (revert) {
_cloneHide(activeSortable, true); _cloneHide(activeSortable, true);
parentEl = rootEl; // actualization parentEl = rootEl; // actualization
if (cloneEl || nextEl) { if (cloneEl || nextEl) {
rootEl.insertBefore(dragEl, cloneEl || nextEl); _insertBefore(rootEl, dragEl, cloneEl || nextEl);
} }
else if (!canSort) { else if (!canSort) {
rootEl.appendChild(dragEl); _insertBefore(rootEl, dragEl, null);
} }
return; return;
} }
if ((el.children.length === 0) || (el.children[0] === ghostEl) || if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
(el === evt.target) && (_ghostIsLast(el, evt)) (el === evt.target) && (_ghostIsLast(el, evt))
) { ) {
@ -803,14 +817,14 @@
return; return;
} }
targetRect = target.getBoundingClientRect(); targetRect = _getBoundingClientRect(target);
} }
_cloneHide(activeSortable, isOwner); _cloneHide(activeSortable, isOwner);
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) { if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) {
if (!dragEl.contains(el)) { if (!dragEl.contains(el)) {
el.appendChild(dragEl); _insertBefore(el, dragEl, null);
parentEl = el; // actualization parentEl = el; // actualization
} }
@ -825,7 +839,7 @@
lastParentCSS = _css(target.parentNode); lastParentCSS = _css(target.parentNode);
} }
targetRect = target.getBoundingClientRect(); targetRect = _getBoundingClientRect(target);
var width = targetRect.right - targetRect.left, var width = targetRect.right - targetRect.left,
height = targetRect.bottom - targetRect.top, height = targetRect.bottom - targetRect.top,
@ -868,9 +882,9 @@
if (!dragEl.contains(el)) { if (!dragEl.contains(el)) {
if (after && !nextSibling) { if (after && !nextSibling) {
el.appendChild(dragEl); _insertBefore(el, dragEl, null);
} else { } else {
target.parentNode.insertBefore(dragEl, after ? nextSibling : target); _insertBefore(null, dragEl, after ? nextSibling : target);
} }
} }
@ -887,10 +901,10 @@
var ms = this.options.animation; var ms = this.options.animation;
if (ms) { if (ms) {
var currentRect = target.getBoundingClientRect(); var currentRect = _getBoundingClientRect(target);
if (prevRect.nodeType === 1) { if (prevRect.nodeType === 1) {
prevRect = prevRect.getBoundingClientRect(); prevRect = _getBoundingClientRect(prevRect);
} }
_css(target, 'transition', 'none'); _css(target, 'transition', 'none');
@ -948,6 +962,22 @@
this._offUpEvents(); this._offUpEvents();
if (lastEl && options.swap) {
_toggleClass(lastEl, options.swapClass, false);
if (dragEl !== lastEl) {
var anchor = dragEl.nextSibling;
var dragRect = _getBoundingClientRect(dragEl);
var lastRect = _getBoundingClientRect(lastEl);
_insertBefore(null, dragEl, lastEl)
_insertBefore(null, lastEl, anchor);
this._animate(dragRect, dragEl);
this._animate(lastRect, lastEl);
}
}
if (evt) { if (evt) {
if (moved) { if (moved) {
evt.preventDefault(); evt.preventDefault();
@ -1120,7 +1150,7 @@
order.forEach(function (id) { order.forEach(function (id) {
if (items[id]) { if (items[id]) {
rootEl.removeChild(items[id]); rootEl.removeChild(items[id]);
rootEl.appendChild(items[id]); _insertBefore(rootEl, items[id], null);
} }
}); });
}, },
@ -1209,10 +1239,10 @@
if (!state) { if (!state) {
if (cloneEl.state) { if (cloneEl.state) {
if (sortable.options.group.revertClone) { if (sortable.options.group.revertClone) {
rootEl.insertBefore(cloneEl, nextEl); _insertBefore(rootEl, cloneEl, nextEl);
sortable._animate(dragEl, cloneEl); sortable._animate(dragEl, cloneEl);
} else { } else {
rootEl.insertBefore(cloneEl, dragEl); _insertBefore(rootEl, cloneEl, dragEl);
} }
} }
} }
@ -1360,7 +1390,7 @@
evt.dragged = dragEl; evt.dragged = dragEl;
evt.draggedRect = dragRect; evt.draggedRect = dragRect;
evt.related = targetEl || toEl; evt.related = targetEl || toEl;
evt.relatedRect = targetRect || toEl.getBoundingClientRect(); evt.relatedRect = targetRect || _getBoundingClientRect(toEl);
evt.willInsertAfter = willInsertAfter; evt.willInsertAfter = willInsertAfter;
evt.originalEvent = originalEvt; evt.originalEvent = originalEvt;
@ -1388,7 +1418,7 @@
/** @returns {HTMLElement|false} */ /** @returns {HTMLElement|false} */
function _ghostIsLast(el, evt) { function _ghostIsLast(el, evt) {
var lastEl = el.lastElementChild, var lastEl = el.lastElementChild,
rect = lastEl.getBoundingClientRect(); rect = _getBoundingClientRect(lastEl);
// 5 — min delta // 5 — min delta
// abs — нельзя добавлять, а то глюки при наведении сверху // abs — нельзя добавлять, а то глюки при наведении сверху
@ -1519,6 +1549,18 @@
return clearTimeout(id); return clearTimeout(id);
} }
function _getBoundingClientRect(el) {
return el.getBoundingClientRect();
}
function _insertBefore(parent, el, ref) {
if (parent === null) {
parent = ref.parentNode;
}
parent.insertBefore(el, ref);
}
// Fixed #973: // Fixed #973:
_on(document, 'touchmove', function (evt) { _on(document, 'touchmove', function (evt) {
if (Sortable.active) { if (Sortable.active) {
@ -1542,7 +1584,9 @@
clone: _clone, clone: _clone,
index: _index, index: _index,
nextTick: _nextTick, nextTick: _nextTick,
cancelNextTick: _cancelNextTick cancelNextTick: _cancelNextTick,
getBoundingClientRect: _getBoundingClientRect,
insertBefore: _insertBefore
}; };

4
st/app.css

@ -241,3 +241,7 @@ img {
#nested ul li { #nested ul li {
background-color: rgba(0,0,0,.05); background-color: rgba(0,0,0,.05);
} }
.sortable-swap-highlight {
background-color: #9AB6F1;
}

Loading…
Cancel
Save