Dragula Multiselect
Let's you select multiple items in a container and drag it to another container.
by gbos
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.css">
<html>
<head>
</head>
<body>
<div class="parent">
<strong>NOTE: Click this panel to give it focus to capture key press events.</strong>
<br/>
<label>Move stuff between these two containers. You can multiselect items on the left by holding down the shift key and clicking items.</label>
<div class="wrapper">
<div id="left" class="container">
<div>Something 1</div>
<div>Something 2</div>
<div>Something 3</div>
<div>Something 4</div>
<div>Something 5</div>
<div>Something 6</div>
<div>Something 7</div>
<div>Something 8</div>
<div>Something 9</div>
</div>
<div id="right" class="container">
<div>Something A</div>
<div>Something B</div>
<div>Something C</div>
<div>Something D</div>
<div>Something E</div>
<div>Something F</div>
<div>Something G</div>
<div>Something H</div>
<div>Something I</div>
</div>
</div>
</div>
</body>
</html>
CSS
body {
background-color: #942A57;
margin: 0 auto;
font-family: Georgia, Helvetica;
font-size: 17px;
color: #ecf0f1;
max-width: 760px;
}
html, body {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*, *:before, *:after {
-webkit-box-sizing: inherit;
-moz-box-sizing: inherit;
box-sizing: inherit;
}
label {
display: block;
font-size: 12px;
font-style: italic;
margin: 5px 0;
}
.parent {
background-color: rgba(255, 255, 255, 0.2);
margin: 50px 0;
padding: 20px;
}
/* dragula-specific example page styles */
.wrapper {
display: table;
width: 100%;
}
.container {
display: table-cell;
background-color: rgba(255, 255, 255, 0.2);
width: 50%;
}
.container:nth-child(odd) {
background-color: rgba(0, 0, 0, 0.2);
}
#right.container .selectedItem {
display: block !important;
}
/*
* note that styling gu-mirror directly is a bad practice because it's too generic.
* you're better off giving the draggable elements a unique class and styling that directly!
*/
.container > div,
.gu-mirror, /* single selection */
.gu-mirror > div /* multiple selection */{
margin: 10px;
padding: 10px;
background-color: rgba(0, 0, 0, 0.2);
transition: opacity 0.4s ease-in-out;
}
.container > div {
cursor: move;
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.gu-mirror {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
transform: rotate(-2deg);
opacity: 0.7;
}
.container > div.selectedItem {
background-color: lightseagreen;
}
.container div.selectedItem.gu-transit {
background-color: rgba(0, 0, 0, 0.5);
}
JavaScript
$(document).ready(function () {
'use strict';
// global references
var left = $('#left'), // left container
right = $('#right'), // right container
hasMultiple = false, // flags if there are multiple selection
selectedItems, // the multiple selections
mirrorContainer, // the floating preview
shiftIsPressed = false; // shift key on keyboard
// setup draggable containers
var drake = dragula([left[0], right[0]], {
revertOnSpill: true
});
// handle events
drake.on('drag', (el) => {
// nothing happening here
})
.on('cloned', (clone, original, type) => {
// are we dragging from left to right?
var isFromLeft = $(original).parent().attr('id') === 'left';
// we're dragging from left to right
if (isFromLeft) {
// grab the mirror container dragula creates by default
mirrorContainer = $('.gu-mirror').first();
// multi selected items will have this class, but we don't want it on the ones in the mirror
mirrorContainer.removeClass('selectedItem');
// get the multi selected items
selectedItems = $('.selectedItem');
// do we have multiple items selected?
// (takes into account edge case where they start dragging from an item that hasn't been selected)
hasMultiple = selectedItems.length > 1 || (selectedItems.length == 1 && !$(original).hasClass('selectedItem'));
// we have multiple items selected
if(hasMultiple) {
// edge case: if they started dragging from an unselected item, adds the selected item class
$('.gu-transit').addClass('selectedItem');
// update list of selected items in case of edge case above
selectedItems = $('.selectedItem');
// clear the mirror container, we're going to fill it with clones of our items
mirrorContainer.empty();
// will track final...