2013-06-03 16 views
10

Próbuję utworzyć kilka elementów, które można przeciągnąć (tokeny), które można przeciągnąć wewnątrz elementu dającego się dostosować. Wygląda na to, że wszystko działa, oprócz tego ... po przeciągnięciu jednego elementu i upuszczeniu go, nie mogę go ponownie przeciągnąć. Wygląda na to, że nie mogę ponownie powiązać z tym wydarzeniem dragstart.Elementy przeciągalne HTML5 w obrębie contenteditable div - przestaje działać po pierwszym dropie - dlaczego?

Każdy pomysł, dlaczego tak się dzieje i jak mogę to naprawić?

Oto link do mojego skrzypce: 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; 
} 
+0

Działa doskonale w Firefoksie, dlatego najprawdopodobniej jest to błąd przeglądarki Chrome. I występuje tylko wtedy, gdy używasz komendy 'insertHTML'. Kiedy zastąpiłem go '$ ('# editor') append (content)' wszystko działa dobrze ... – Reinmar

Odpowiedz

8

Próbowałem również kilku hacków, ale żaden z nich nie działa. Sprawdzałem kod HTML i odkryłem, że w tym przykładzie nowo wstawiona treść nie ma przypisanego atrybutu contenteditable, a kiedy zostałem przypisany do niego ręcznie, to zaczęło działać poprawnie.

Oto mój kod http://jsfiddle.net/gXScu/8/

Właśnie dodałem tę linię

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

Zgadzam się z wyjaśnieniem Reinmar nad contenteditable.

+0

+1. Powinienem to zauważyć :). – Reinmar

+1

@Reinmar: :-). Wydaje się więc, że jeśli zrobimy "insertHTML" przez "dokument.execCommand "następnie Chrome usuwa po cichu atrybut contenteditable :-). –

+0

Zarówno Firefox, jak i Chrome mogą dawać niespójne wyniki przy użyciu "document.execCommand (" insertHTML ", false, content); '. Aby to naprawić, zmień go na "pasteHtmlAtCaret (content)". Funkcję można znaleźć tutaj: http://stackoverflow.com/questions/6690752/insert-html-at-caret-in-a-contenteditable-div/6691294#6691294 – castt

1

Widocznie Chrome ma błąd (nie jest zaskoczeniem - contenteditable to najbardziej błędna funkcja we wszystkich przeglądarkach). Twój kod działa doskonale w Firefoksie, ale z jakiegoś powodu nie można przeciągnąć elementu wstawionego do edycji za pomocą polecenia insertHTML.

Próbowałem kilka hacków, ale tylko jeden działał - wstawiając inny element, a następnie go zastępując.

Więc zamiast:

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

użyć czegoś takiego:

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

Można spróbować to tutaj: http://jsfiddle.net/gXScu/5/. Poprawiłem również niewłaściwą kolejność tego:

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

To jest całkowicie poprawna odpowiedź i dobre wytłumaczenie, dziękuję! Jednak wybrałem odpowiedź Imrana, ponieważ jest nieco prostsza i nie wymaga tworzenia dodatkowego elementu. – ragulka

+0

Jedną rzeczą, która może być brakująca imho, jest wskaźnik wskazujący miejsce, w którym przedmiot ma zostać umieszczony po mouseup. Czy to jakoś możliwe? – displayname

Powiązane problemy