Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dragula dropping a different element than dragged

In dragula you have a potential one way copy from one container to another - I want to use this for a UI where you drag a symbol representing an element into a container and have it spawn the "Real deal" - real deal being an arbitrary different element.

Most of this was really easy:

dragula([].slice.call(document.querySelectorAll('.container')), {
  copy: function (el, source) {
    return source === document.getElementById('c1')
  },
  accepts: function (el, target) {
    return target !== document.getElementById('c1')
  },
  removeOnSpill: true
}).on('drop', function (el) {
    var newNode = document.createElement("div");
    newNode.textContent = "The real deal";
    newNode.classList.add("elem");
    el.parentNode.replaceChild(newNode, el);
});
.container {
  border: 1px solid #000;
  min-height:50px;
  background:#EEE;
}
.elem {
  padding:10px;
  border: 1px solid #000;
  background:#FFF;
  margin:5px;
  display: inline-block;
}
<div id="c1" class="container">
  <div class="elem">Icon1</div>
  <div class="elem">Icon2</div>
  <div class="elem">Icon3</div>
  <div class="elem">Icon4</div>
  <div class="elem">Icon5</div>
  <div class="elem">Icon6</div>
</div>
<div id="c2" class="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.6.8/dragula.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.6.8/dragula.min.css" rel="stylesheet"
      />

As you can see - this replaces the element on drop giving me the result I want. However, the ghost image while dragging is still the original "Symbol" element.

Is it possible to replace the "To be dropped" element on drag so that both the ghost and the final result look like the required element?

like image 881
J V Avatar asked Mar 23 '16 17:03

J V


1 Answers

There's a shadow event that triggers repeatedly during drag. I thought I could use it to replace the shadow element but it appears dragula keeps a reference to it so if I remove it it will stop working.

Apparently the cleanest way to get around this is to set the original ghost to display: none and put another one down next to it, then clean it up on dragend.

I have no idea if size differences between the real and fake shadow element will break positioning. I'll cross that bridge when I get to it.

function makeElement(){
    var newNode = document.createElement("div");
    newNode.textContent = "Wootley!";
    newNode.classList.add("elem");
    return newNode;
}

dragula([].slice.call(document.querySelectorAll('.container')), {
  copy: function (el, source) {
    return source === document.getElementById('c1')
  },
  accepts: function (el, target) {
    return target !== document.getElementById('c1')
  },
  removeOnSpill: true
}).on('dragend', function (el) {
    this._shadow.remove();
    this._shadow = null;
}).on('drop', function (el) {
    el.parentNode.replaceChild(makeElement(), el);
}).on('shadow', function(el, target){
    if (!this._shadow){
        this._shadow = makeElement();
        this._shadow.classList.add("gu-transit");
    }
    el.style.display = 'none';
    el.parentNode.insertBefore(this._shadow, el);
});
.container {
  border: 1px solid #000;
  min-height:50px;
  background:#EEE;
}
.elem {
  padding:10px;
  border: 1px solid #000;
  background:#FFF;
  margin:5px;
  display: inline-block;
}
<div id="c1" class="container">
  <div class="elem">Icon1</div>
  <div class="elem">Icon2</div>
  <div class="elem">Icon3</div>
  <div class="elem">Icon4</div>
  <div class="elem">Icon5</div>
  <div class="elem">Icon6</div>
</div>
<div id="c2" class="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.6.8/dragula.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.6.8/dragula.min.css" rel="stylesheet"
      />
like image 192
J V Avatar answered Nov 02 '22 06:11

J V