Browse Source

Swap Feature

This is a rough implementation of a swapping feature. Setting the new "swap" option to true will cause a dragged item to be swapped with the item you drop it on (instead of inserted next to it). The item being hovered over (and potentially swapped with) will be highlighted by adding the class specified in the new "swapHighlightClass" option (defaults to "sortable-swap-highlight"). When swapping is enabled, the "end" event's "to" property will be set to the item being dropped on and swapped with.

It's a bit hackish, but it works as a solution to issues #1211, #1082, #1072, #891, #869, and #469. Maybe it can at least serve as a starting off point to adding this feature to master eventually? Thanks!
pull/1274/head
Ken 7 years ago committed by GitHub
parent
commit
aa6e99ef9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 118
      Sortable.js

118
Sortable.js

@ -261,6 +261,7 @@
var defaults = { var defaults = {
group: null, group: null,
sort: true, sort: true,
swap: false,
disabled: false, disabled: false,
store: null, store: null,
handle: null, handle: null,
@ -271,6 +272,7 @@
ghostClass: 'sortable-ghost', ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen', chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag', dragClass: 'sortable-drag',
swapHighlightClass: 'sortable-swap-highlight',
ignore: 'a, img', ignore: 'a, img',
filter: null, filter: null,
preventOnFilter: true, preventOnFilter: true,
@ -860,10 +862,21 @@
_cloneHide(activeSortable, isOwner); _cloneHide(activeSortable, isOwner);
if (!dragEl.contains(el)) { if (!dragEl.contains(el)) {
if (after && !nextSibling) { if (this.options.swap)
el.appendChild(dragEl); {
} else { var elements = document.getElementsByClassName(this.options.swapHighlightClass);
target.parentNode.insertBefore(dragEl, after ? nextSibling : target); while(elements.length > 0){
_toggleClass(elements[0], this.options.swapHighlightClass, false);
}
_toggleClass(target, this.options.swapHighlightClass, true);
}
else
{
if (after && !nextSibling) {
el.appendChild(dragEl);
} else {
target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
}
} }
} }
@ -969,44 +982,63 @@
// Drag stop event // Drag stop event
_dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex, null, evt); _dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex, null, evt);
if (rootEl !== parentEl) { if (this.options.swap)
newIndex = _index(dragEl, options.draggable); {
var elements = document.getElementsByClassName(this.options.swapHighlightClass);
if (newIndex >= 0) { var dropEl = null;
// Add event while(elements.length > 0){
_dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); dropEl = elements[0];
_toggleClass(elements[0], this.options.swapHighlightClass, false);
// Remove event }
_dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
// drag from one list and drop into another if (dropEl)
_dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); {
_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); _swapNodes(dragEl, dropEl);
newIndex = _index(dragEl, options.draggable);
_dispatchEvent(this, rootEl, 'end', dragEl, dropEl, rootEl, oldIndex, newIndex);
} }
} }
else { else
if (dragEl.nextSibling !== nextEl) { {
// Get the index of the dragged element within its parent if (rootEl !== parentEl) {
newIndex = _index(dragEl, options.draggable); newIndex = _index(dragEl, options.draggable);
if (newIndex >= 0) { if (newIndex >= 0) {
// drag & drop within the same list // Add event
_dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); _dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
// Remove event
_dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
// drag from one list and drop into another
_dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); _dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
} }
} }
} else {
if (dragEl.nextSibling !== nextEl) {
if (Sortable.active) { // Get the index of the dragged element within its parent
/* jshint eqnull:true */ newIndex = _index(dragEl, options.draggable);
if (newIndex == null || newIndex === -1) {
newIndex = oldIndex; if (newIndex >= 0) {
// drag & drop within the same list
_dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
}
}
} }
_dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex, evt); if (Sortable.active) {
/* jshint eqnull:true */
if (newIndex == null || newIndex === -1) {
newIndex = oldIndex;
}
_dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex, evt);
// Save sorting // Save sorting
this.save(); this.save();
}
} }
} }
@ -1511,6 +1543,32 @@
function _cancelNextTick(id) { function _cancelNextTick(id) {
return clearTimeout(id); return clearTimeout(id);
} }
function _swapNodes(n1, n2) {
var p1 = n1.parentNode;
var p2 = n2.parentNode;
var i1, i2;
if ( !p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1) ) return;
for (var i = 0; i < p1.children.length; i++) {
if (p1.children[i].isEqualNode(n1)) {
i1 = i;
}
}
for (var i = 0; i < p2.children.length; i++) {
if (p2.children[i].isEqualNode(n2)) {
i2 = i;
}
}
if ( p1.isEqualNode(p2) && i1 < i2 ) {
i2++;
}
p1.insertBefore(n2, p1.children[i1]);
p2.insertBefore(n1, p2.children[i2]);
}
// Fixed #973: // Fixed #973:
_on(document, 'touchmove', function (evt) { _on(document, 'touchmove', function (evt) {

Loading…
Cancel
Save