Skip to content

Commit 355da84

Browse files
committed
multidrag select across sortables
1 parent babf6ab commit 355da84

File tree

1 file changed

+113
-31
lines changed

1 file changed

+113
-31
lines changed

plugins/MultiDrag/MultiDrag.js

+113-31
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
setRect,
1111
unsetRect,
1212
matrix,
13-
expando
13+
expando,
14+
getParentOrHost,
1415
} from '../../src/utils.js';
1516

1617
import dispatchEvent from '../../src/EventDispatcher.js';
@@ -19,6 +20,7 @@ let multiDragElements = [],
1920
multiDragClones = [],
2021
lastMultiDragSelect, // for selection with modifier key down (SHIFT)
2122
multiDragSortable,
23+
multiDragGroupMembers = {},
2224
initialFolding = false, // Initial multi-drag fold when drag started
2325
folding = false, // Folding any other time
2426
dragStarted = false,
@@ -44,6 +46,14 @@ function MultiDragPlugin() {
4446
}
4547
}
4648

49+
if (sortable.options.group) {
50+
const group = typeof sortable.options.group === 'string' ? { name: sortable.options.group } : sortable.options.group;
51+
if (multiDragGroupMembers[group.name] === undefined) {
52+
multiDragGroupMembers[group.name] = [];
53+
}
54+
multiDragGroupMembers[group.name].push(sortable);
55+
}
56+
4757
on(document, 'keydown', this._checkKeyDown);
4858
on(document, 'keyup', this._checkKeyUp);
4959

@@ -69,7 +79,6 @@ function MultiDragPlugin() {
6979
multiDragKeyDown: false,
7080
isMultiDrag: false,
7181

72-
7382
delayStartGlobal({ dragEl: dragged }) {
7483
dragEl = dragged;
7584
},
@@ -84,6 +93,7 @@ function MultiDragPlugin() {
8493
multiDragClones.push(clone(multiDragElements[i]));
8594

8695
multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
96+
multiDragClones[i].sortableParentEl = multiDragElements[i].sortableParentEl;
8797

8898
multiDragClones[i].draggable = false;
8999
multiDragClones[i].style['will-change'] = '';
@@ -136,11 +146,12 @@ function MultiDragPlugin() {
136146

137147
dragStartGlobal({ sortable }) {
138148
if (!this.isMultiDrag && multiDragSortable) {
139-
multiDragSortable.multiDrag._deselectMultiDrag();
149+
MultiDrag.utils.clear();
140150
}
141151

142152
multiDragElements.forEach(multiDragElement => {
143153
multiDragElement.sortableIndex = index(multiDragElement);
154+
multiDragElement.sortableParentEl = getParentOrHost(multiDragElement);
144155
});
145156

146157
// Sort multi-drag elements
@@ -197,10 +208,46 @@ function MultiDragPlugin() {
197208
});
198209
},
199210

200-
dragOver({ target, completed, cancel }) {
211+
dragOver({ target, completed, cancel, originalEvent }) {
201212
if (folding && ~multiDragElements.indexOf(target)) {
202213
completed(false);
203214
cancel();
215+
return;
216+
}
217+
218+
const toSortable = target.parentNode[expando];
219+
220+
if (!toSortable || multiDragElements.length === 0) {
221+
return;
222+
}
223+
224+
let checkPut;
225+
226+
if (toSortable.options.group) {
227+
checkPut = toSortable.options.group.checkPut;
228+
}
229+
230+
const forbiddenMove = ~multiDragElements.findIndex((el) => {
231+
if (!el.sortableParentEl) {
232+
return false;
233+
}
234+
235+
const fromSortable = el.sortableParentEl[expando];
236+
237+
if (fromSortable && fromSortable.options.group && !fromSortable.options.group.checkPull(toSortable, fromSortable, el, originalEvent)) {
238+
return true;
239+
}
240+
241+
if (checkPut && !checkPut(toSortable, fromSortable, el, originalEvent)) {
242+
return true;
243+
}
244+
245+
return false;
246+
});
247+
248+
if (forbiddenMove) {
249+
completed(false);
250+
cancel();
204251
}
205252
},
206253

@@ -311,7 +358,7 @@ function MultiDragPlugin() {
311358
// Multi-drag selection
312359
if (!dragStarted) {
313360
if (options.multiDragKey && !this.multiDragKeyDown) {
314-
this._deselectMultiDrag();
361+
MultiDrag.utils.clear();
315362
}
316363
toggleClass(dragEl, options.selectedClass, !~multiDragElements.indexOf(dragEl));
317364

@@ -461,39 +508,38 @@ function MultiDragPlugin() {
461508
},
462509

463510
destroyGlobal() {
464-
this._deselectMultiDrag();
511+
MultiDrag.utils.clear();
512+
465513
off(document, 'pointerup', this._deselectMultiDrag);
466514
off(document, 'mouseup', this._deselectMultiDrag);
467515
off(document, 'touchend', this._deselectMultiDrag);
468516

469517
off(document, 'keydown', this._checkKeyDown);
470518
off(document, 'keyup', this._checkKeyUp);
519+
520+
const groupMembers = findAllMembersInSortableGroup(this.sortable);
521+
522+
if (groupMembers) {
523+
let membersIndex;
524+
if (~(membersIndex = groupMembers.indexOf(this.sortable))) {
525+
groupMembers.splice(membersIndex, 1);
526+
}
527+
}
471528
},
472529

473530
_deselectMultiDrag(evt) {
474-
if (typeof dragStarted !== "undefined" && dragStarted) return;
475-
476531
// Only deselect if selection is in this sortable
477532
if (multiDragSortable !== this.sortable) return;
478533

479-
// Only deselect if target is not item in this sortable
480-
if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;
481-
482-
// Only deselect if left click
483-
if (evt && evt.button !== 0) return;
484-
485-
while (multiDragElements.length) {
486-
let el = multiDragElements[0];
487-
toggleClass(el, this.options.selectedClass, false);
488-
multiDragElements.shift();
489-
dispatchEvent({
490-
sortable: this.sortable,
491-
rootEl: this.sortable.el,
492-
name: 'deselect',
493-
targetEl: el,
494-
originalEvent: evt
495-
});
534+
if (evt) {
535+
// Only deselect if left click
536+
if (evt.button !== 0) return;
537+
538+
// Only deselect if target is not item in any sortable in group (including this)
539+
if (itemElIsInSortableGroup(evt.target, this.sortable)) return;
496540
}
541+
542+
MultiDrag.utils.clear(evt);
497543
},
498544

499545
_checkKeyDown(evt) {
@@ -521,7 +567,9 @@ function MultiDragPlugin() {
521567
let sortable = el.parentNode[expando];
522568
if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
523569
if (multiDragSortable && multiDragSortable !== sortable) {
524-
multiDragSortable.multiDrag._deselectMultiDrag();
570+
if (!itemElIsInSortableGroup(el, multiDragSortable)) {
571+
MultiDrag.utils.clear();
572+
}
525573
multiDragSortable = sortable;
526574
}
527575
toggleClass(el, sortable.options.selectedClass, true);
@@ -537,6 +585,24 @@ function MultiDragPlugin() {
537585
if (!sortable || !sortable.options.multiDrag || !~index) return;
538586
toggleClass(el, sortable.options.selectedClass, false);
539587
multiDragElements.splice(index, 1);
588+
},
589+
clear(evt) {
590+
if (typeof dragStarted !== "undefined" && dragStarted) return;
591+
592+
while (multiDragElements.length) {
593+
const el = multiDragElements[0];
594+
const sortableEl = getParentOrHost(el);
595+
const sortable = sortableEl[expando];
596+
toggleClass(el, sortable.options.selectedClass, false);
597+
multiDragElements.shift();
598+
dispatchEvent({
599+
sortable: sortable,
600+
rootEl: sortableEl,
601+
name: 'deselect',
602+
targetEl: el,
603+
originalEvent: evt
604+
});
605+
}
540606
}
541607
},
542608
eventProperties() {
@@ -546,6 +612,7 @@ function MultiDragPlugin() {
546612
multiDragElements.forEach(multiDragElement => {
547613
oldIndicies.push({
548614
multiDragElement,
615+
parentElement: multiDragElement.sortableParentEl,
549616
index: multiDragElement.sortableIndex
550617
});
551618

@@ -560,9 +627,11 @@ function MultiDragPlugin() {
560627
}
561628
newIndicies.push({
562629
multiDragElement,
630+
parentElement: multiDragElement.sortableParentEl,
563631
index: newIndex
564632
});
565633
});
634+
566635
return {
567636
items: [...multiDragElements],
568637
clones: [...multiDragClones],
@@ -572,11 +641,13 @@ function MultiDragPlugin() {
572641
},
573642
optionListeners: {
574643
multiDragKey(key) {
575-
key = key.toLowerCase();
576-
if (key === 'ctrl') {
577-
key = 'Control';
578-
} else if (key.length > 1) {
579-
key = key.charAt(0).toUpperCase() + key.substr(1);
644+
if (typeof key === 'string') {
645+
key = key.toLowerCase();
646+
if (key === 'ctrl') {
647+
key = 'Control';
648+
} else if (key.length > 1) {
649+
key = key.charAt(0).toUpperCase() + key.substr(1);
650+
}
580651
}
581652
return key;
582653
}
@@ -618,4 +689,15 @@ function removeMultiDragElements() {
618689
});
619690
}
620691

692+
function findAllMembersInSortableGroup(sortable) {
693+
if (!sortable.options.group) {
694+
return null;
695+
}
696+
return multiDragGroupMembers[sortable.options.group.name] || [];
697+
}
698+
699+
function itemElIsInSortableGroup(itemEl, sortable) {
700+
return ~(findAllMembersInSortableGroup(sortable) || [sortable]).findIndex((sortable) => closest(itemEl, sortable.options.draggable, sortable.el, false));
701+
}
702+
621703
export default MultiDragPlugin;

0 commit comments

Comments
 (0)