Перетаскиваемые элементы HTML5 внутри contenteditable div-stop работают после первого падения - почему?

Я пытаюсь создать несколько перетаскиваемых элементов (токенов), которые можно перетаскивать внутри contenteditable div. Кажется, что все работает, кроме этого... после того, как я перетащил один элемент и уронил его, я больше не могу его перетащить. Кажется, что я не могу привязываться к этому событию dragstart снова.

Любая идея, почему это происходит и как я могу ее исправить?

Здесь ссылка на мою скрипку: 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;
}

Ответ 1

Я также попробовал несколько хаков, но ни один из них не работает. Я проверял HTML, и я обнаружил, что в вашем примере недавно вставленный контент не имеет назначенного contenteditable атрибута и когда я назначил его вручную, тогда он начал работать нормально.

Вот мой код http://jsfiddle.net/gXScu/8/

Я просто добавил эту строку

$('.draggable').attr("contenteditable", false); в bindDraggables.

Я согласен с объяснением Рейнмара над contenteditable.

Ответ 2

По-видимому, Chrome имеет ошибку (не удивительно - contenteditable - самая глючная функция во всех браузерах). Ваш код отлично работает в Firefox, но по какой-то причине элемент, вставленный в редактируемый с помощью команды insertHTML, больше нельзя перетаскивать.

Я пробовал несколько хаков, но только один работал - вставлял другой элемент, а затем заменял его.

Итак, вместо этого:

document.execCommand('insertHTML', false, content);

Используйте что-то вроде этого:

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);

Вы можете попробовать это здесь: http://jsfiddle.net/gXScu/5/. Я также исправил неправильный порядок:

$('.dragged').remove();
bindDraggables();