I am trying to create a few draggable elements (tokens) that can be dragged around inside a contenteditable div. It seems that everything is working except that... after I drag one element and drop it, I cannot drag it again. It seems that I cannot bind to it's dragstart event again.
Any idea why this happens and how can i fix it?
Here's a link to my fiddle: http://jsfiddle.net/gXScu/1/
HTML:
<div id="editor" contenteditable="true">
Testime siinkohal seda, et kuidas<br />
on võimalik asja testida.
<span class="draggable" draggable="true" contenteditable="false">Token</span>
</div>
<span class="draggable" draggable="true" contenteditable="false">Token 2</span>
Javascript (jQuery)
var bindDraggables = function() {
console.log('binding draggables', $('.draggable').length);
$('.draggable').off('dragstart').on('dragstart', function(e) {
if (!e.target.id)
e.target.id = (new Date()).getTime();
e.originalEvent.dataTransfer.setData('text/html', e.target.outerHTML);
console.log('started dragging');
$(e.target).addClass('dragged');
}).on('click', function() {
console.log('there was a click');
});
}
$('#editor').on('dragover', function (e) {
e.preventDefault();
return false;
});
$('#editor').on('drop', function(e) {
e.preventDefault();
var e = e.originalEvent;
var content = e.dataTransfer.getData('text/html');
var range = null;
if (document.caretRangeFromPoint) { // Chrome
range = document.caretRangeFromPoint(e.clientX, e.clientY);
}
else if (e.rangeParent) { // Firefox
range = document.createRange();
range.setStart(e.rangeParent, e.rangeOffset);
}
console.log('range', range)
var sel = window.getSelection();
sel.removeAllRanges(); sel.addRange(range);
$('#editor').get(0).focus(); // essential
document.execCommand('insertHTML',false, content);
//$('#editor').append(content);
sel.removeAllRanges();
bindDraggables();
console.log($('[dragged="dragged"]').length);
$('.dragged').remove();
});
bindDraggables();
CSS:
#editor {
border: 2px solid red;
padding: 5px;
}
.draggable {
display: inline-block;
padding: 3px;
background: yellow;
cursor: move !important;
}
I also tried a few hacks but none of them seems to work. I was inspecting HTML and I found that in your example the newly inserted content don't have any contenteditable attribute assigned and when I assigned to it manually then it started working fine.
Here is my code http://jsfiddle.net/gXScu/8/
I just added this line
$('.draggable').attr("contenteditable", false);
in bindDraggables
method.
I agree with Reinmar explanation over contenteditable.
Apparently Chrome has a bug (not a surprise - contenteditable
is the most buggy feature in all browsers). Your code works perfectly fine on Firefox, but for some reason element inserted into editable with insertHTML
command cannot be dragged any more.
I tried few hacks, but only one worked - inserting other element and then replacing it.
So instead:
document.execCommand('insertHTML', false, content);
Use something like this:
var spanId = 'temp-' + (new Date()).getTime();
// Insert span with zero-width space (so it isn't visible and it isn't empty).
document.execCommand('insertHTML', false, '<span id="' + spanId + '">\u200b</span>');
// Replace that span with our dragged content.
$('#' + spanId).replaceWith(content);
You can try this here: http://jsfiddle.net/gXScu/5/. I also corrected wrong order of this:
$('.dragged').remove();
bindDraggables();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With