4

If one drags an element from within a contenteditable the browser usually shows such an "intermediate caret" as can be seen in the image below:

enter image description here

I am looking for a simple and reliable solution to drag an element from within a contenteditable by sending the elements ID as transfer data via drag and drop. Then, in the ondrop method I intend to place the draggable at the exact position where this "intermediate caret" is currently at.

The question is: Will I be able to get this information from all the browsers?

I do have a base (JSFiddle) but that's far from being useful for me at the moment.

PS: I am not using jQuery or any other libraries.

Stefan Falk
  • 23,898
  • 50
  • 191
  • 378
  • 5
    i was able to craft this: https://jsfiddle.net/jkLhfzr8/, is that like what you want? – dandavis Mar 24 '16 at 17:42
  • @dandavis omg this is genius! This should work on all browsers, right? This looks like chances are good that most of them are going to support this.. I am looking for a simple solution for days now and the most promising solution so far was [this](http://stackoverflow.com/questions/14678451/precise-drag-and-drop-within-a-contenteditable) .. I was thinking about simply switching the elements too but I would not have been able to do that. Let me check this solution a bit but this looks like **the** answer for me! :) – Stefan Falk Mar 24 '16 at 17:54
  • @dandavis Thanks man! I think I'll go with that and please write a blog or something about this because honestly.. doing something that simple really took me a while to find out how. You could also provide your answer [here](http://stackoverflow.com/questions/36201878/why-am-i-not-able-to-drag-the-span-but-instead-the-img) since they are closely related. – Stefan Falk Mar 24 '16 at 18:03
  • 1
    i think it would work on all DND browsers, i even avoided `elm.remove()` and used the backwards-compat `parent.removeChild` instead... – dandavis Mar 24 '16 at 18:20
  • @dandavis Great! Feel free to provide an answer! :) – Stefan Falk Mar 24 '16 at 18:28

1 Answers1

1

Check out document.caretRangeFromPoint and e.rangeParent, e.rangeOffset.

Here is a demo https://jsfiddle.net/znghofxt

function dragElement(e) {
  e.dataTransfer.setData('text/plain', e.target.id);
}

function drop(e) {
  e.preventDefault();
  var id = e.dataTransfer.getData("text/plain");
  if (document.caretRangeFromPoint) {
    // edge, chrome, android
    range = document.caretRangeFromPoint(e.clientX, e.clientY)
  } else {
    // firefox
    var pos = [e.rangeParent, e.rangeOffset]
    range = document.createRange()
    range.setStart(...pos);
    range.setEnd(...pos);
  }

  range.insertNode(document.getElementById(id));
}
.fancy {
  background-color: #123456;
  color: white;
  border-radius: 8px 8px 8px 8px;
  cursor:pointer; 
  display: inline-block;
  padding: 20px;
}

.fancy-img {
  cursor:pointer; 
  display: inline-block;
}
<div contenteditable="true" ondrop="drop(event)">   
  More blah
  about 
  <a id="dragme" href="http://www.google.com" class="fancy" contenteditable="false" ondragstart="dragElement(event)">       
    :(
  </a>
  Sparta!
</div>
  • this is Genius. Any change there we could change drop position to end of word (avoiding it to be set int the middle of it)? – calebmiranda May 31 '23 at 21:43