From fccf6e689d5b41990027d9bd202e8fe49afca974 Mon Sep 17 00:00:00 2001 From: Roy Mdr Date: Mon, 29 Aug 2022 18:59:19 -0500 Subject: [PATCH 1/2] Add option for reverting DOM modifications This option allows to use Sortable.js with any framework that handles the DOM manipulation by state (React, Vue, Svelte...). Toggling the option 'revertDOM' to 'true' will let you handle your own state manipulation by the Sortable events (onAdd, onSort...). Now the events also receive the Sortable object, allowing access to the 'to' and 'from' group names and other properties. --- src/EventDispatcher.js | 4 ++- src/Sortable.js | 70 +++++++++++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/src/EventDispatcher.js b/src/EventDispatcher.js index e47cb5809..97af71d74 100644 --- a/src/EventDispatcher.js +++ b/src/EventDispatcher.js @@ -5,7 +5,7 @@ import PluginManager from './PluginManager.js'; export default function dispatchEvent( { sortable, rootEl, name, - targetEl, cloneEl, toEl, fromEl, + targetEl, cloneEl, toEl, toSortable, fromEl, fromSortable, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, originalEvent, putSortable, extraEventProperties @@ -29,7 +29,9 @@ export default function dispatchEvent( } evt.to = toEl || rootEl; + evt.toSortable = toSortable || undefined; evt.from = fromEl || rootEl; + evt.fromSortable = fromSortable || undefined; evt.item = targetEl || rootEl; evt.clone = cloneEl; diff --git a/src/Sortable.js b/src/Sortable.js index 7a8c779b8..5655002d5 100644 --- a/src/Sortable.js +++ b/src/Sortable.js @@ -358,6 +358,7 @@ function Sortable(el, options) { let defaults = { group: null, + revertDOM: false, sort: true, disabled: false, store: null, @@ -1426,12 +1427,31 @@ Sortable.prototype = /** @lends Sortable.prototype */ { if (rootEl !== parentEl) { if (newIndex >= 0) { + // drag from one list and drop into another + + /* ----- */ + + if (parentEl[expando].options.revertDOM) { + parentEl.removeChild(dragEl); + } + + if (rootEl[expando].options.revertDOM) { + rootEl.insertBefore(dragEl, rootEl.children[oldIndex]); + if (putSortable.lastPutMode === 'clone') { + rootEl.removeChild(cloneEl); + } + } + + /* ----- */ + // Add event _dispatchEvent({ rootEl: parentEl, name: 'add', toEl: parentEl, + toSortable: parentEl[expando], fromEl: rootEl, + fromSortable: rootEl[expando], originalEvent: evt }); @@ -1440,24 +1460,31 @@ Sortable.prototype = /** @lends Sortable.prototype */ { sortable: this, name: 'remove', toEl: parentEl, + toSortable: parentEl[expando], originalEvent: evt }); - // drag from one list and drop into another - _dispatchEvent({ - rootEl: parentEl, - name: 'sort', - toEl: parentEl, - fromEl: rootEl, - originalEvent: evt - }); + if (!parentEl[expando].options.revertDOM) { + _dispatchEvent({ + rootEl: parentEl, + name: 'sort', + toEl: parentEl, + toSortable: parentEl[expando], + fromEl: rootEl, + fromSortable: rootEl[expando], + originalEvent: evt + }); + } - _dispatchEvent({ - sortable: this, - name: 'sort', - toEl: parentEl, - originalEvent: evt - }); + if (!rootEl[expando].options.revertDOM) { + _dispatchEvent({ + sortable: this, + name: 'sort', + toEl: parentEl, + toSortable: parentEl[expando], + originalEvent: evt + }); + } } putSortable && putSortable.save(); @@ -1465,10 +1492,24 @@ Sortable.prototype = /** @lends Sortable.prototype */ { if (newIndex !== oldIndex) { if (newIndex >= 0) { // drag & drop within the same list + + /* ----- */ + + if (parentEl[expando].options.revertDOM) { + parentEl.removeChild(dragEl); + } + + if (rootEl[expando].options.revertDOM) { + rootEl.insertBefore(dragEl, rootEl.children[oldIndex]); + } + + /* ----- */ + _dispatchEvent({ sortable: this, name: 'update', toEl: parentEl, + toSortable: parentEl[expando], originalEvent: evt }); @@ -1476,6 +1517,7 @@ Sortable.prototype = /** @lends Sortable.prototype */ { sortable: this, name: 'sort', toEl: parentEl, + toSortable: parentEl[expando], originalEvent: evt }); } From cee2ee7bccf83a7776c85588759aa0b8f9ca5d3f Mon Sep 17 00:00:00 2001 From: Roy Mdr Date: Sat, 10 Sep 2022 15:55:04 -0500 Subject: [PATCH 2/2] Add MultiDrag Plugin support --- src/EventDispatcher.js | 5 ++- src/Sortable.js | 99 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/EventDispatcher.js b/src/EventDispatcher.js index 97af71d74..cc7ee4310 100644 --- a/src/EventDispatcher.js +++ b/src/EventDispatcher.js @@ -8,7 +8,8 @@ export default function dispatchEvent( targetEl, cloneEl, toEl, toSortable, fromEl, fromSortable, oldIndex, newIndex, oldDraggableIndex, newDraggableIndex, - originalEvent, putSortable, extraEventProperties + originalEvent, putSortable, extraEventProperties, + originalAllEventProperties } ) { sortable = (sortable || (rootEl && rootEl[expando])); @@ -46,7 +47,7 @@ export default function dispatchEvent( let allEventProperties = { ...extraEventProperties, ...PluginManager.getEventProperties(name, sortable) }; for (let option in allEventProperties) { - evt[option] = allEventProperties[option]; + evt[option] = originalAllEventProperties ? originalAllEventProperties[option] : allEventProperties[option]; } if (rootEl) { diff --git a/src/Sortable.js b/src/Sortable.js index 5655002d5..a9cc7a275 100644 --- a/src/Sortable.js +++ b/src/Sortable.js @@ -87,6 +87,7 @@ function _dispatchEvent(info) { oldDraggableIndex, newIndex, newDraggableIndex, + originalAllEventProperties, ...info }); } @@ -110,6 +111,8 @@ let dragEl, activeGroup, putSortable, + originalAllEventProperties, + awaitingDragStarted = false, ignoreNextClick = false, sortables = [], @@ -1423,6 +1426,8 @@ Sortable.prototype = /** @lends Sortable.prototype */ { originalEvent: evt }); + const allEventProperties = PluginManager.getEventProperties(null, rootEl[expando]); + originalAllEventProperties = allEventProperties; if (rootEl !== parentEl) { @@ -1431,14 +1436,52 @@ Sortable.prototype = /** @lends Sortable.prototype */ { /* ----- */ - if (parentEl[expando].options.revertDOM) { - parentEl.removeChild(dragEl); - } + if (allEventProperties.hasOwnProperty("items") && allEventProperties.items.length > 0) { + // Multidrag Plugin + + if (parentEl[expando].options.revertDOM) { + // Remove added elements in new list + for (const el of allEventProperties.items) { + if (parentEl.contains(el)) { + parentEl.removeChild(el); + } + } + } - if (rootEl[expando].options.revertDOM) { - rootEl.insertBefore(dragEl, rootEl.children[oldIndex]); - if (putSortable.lastPutMode === 'clone') { - rootEl.removeChild(cloneEl); + if (rootEl[expando].options.revertDOM) { + // Return items back to original list + if (putSortable.lastPutMode === 'clone') { + for (const cl of allEventProperties.clones) { + if (rootEl.contains(cl)) { + rootEl.removeChild(cl); + } + } + } + + for (let m = 0; m < allEventProperties.items.length; m++) { + const multEl = allEventProperties.items[m]; + const prevIx = allEventProperties.oldIndicies[m].index; + if (!parentEl.contains(multEl)) { + rootEl.insertBefore(multEl, rootEl.children[prevIx]); + } + Sortable.utils.deselect(multEl); + } + } + + } else { + // Normal Sortable (Not Multidrag Plugin) + + if (parentEl[expando].options.revertDOM) { + // Remove added elements in new list + parentEl.removeChild(dragEl); + } + + if (rootEl[expando].options.revertDOM) { + // Return items back to original list + if (putSortable.lastPutMode === 'clone') { + rootEl.removeChild(cloneEl); + } + rootEl.insertBefore(dragEl, rootEl.children[oldIndex]); } } @@ -1495,12 +1538,42 @@ Sortable.prototype = /** @lends Sortable.prototype */ { /* ----- */ - if (parentEl[expando].options.revertDOM) { - parentEl.removeChild(dragEl); - } - - if (rootEl[expando].options.revertDOM) { - rootEl.insertBefore(dragEl, rootEl.children[oldIndex]); + if (allEventProperties.hasOwnProperty("items") && allEventProperties.items.length > 0) { + // Multidrag Plugin + + if (parentEl[expando].options.revertDOM) { + // Remove added elements in new list + for (const el of allEventProperties.items) { + if (parentEl.contains(el)) { + parentEl.removeChild(el); + } + } + } + + if (rootEl[expando].options.revertDOM) { + // Return items back to original list + for (let m = 0; m < allEventProperties.items.length; m++) { + const multEl = allEventProperties.items[m]; + const prevIx = allEventProperties.oldIndicies[m].index; + if (!parentEl.contains(multEl)) { + rootEl.insertBefore(multEl, rootEl.children[prevIx]); + } + Sortable.utils.deselect(multEl); + } + } + + } else { + // Normal Sortable (Not Multidrag Plugin) + + if (parentEl[expando].options.revertDOM) { + // Remove added elements in new list + parentEl.removeChild(dragEl); + } + + if (rootEl[expando].options.revertDOM) { + // Return items back to original list + rootEl.insertBefore(dragEl, rootEl.children[oldIndex]); + } } /* ----- */