Не удается запустить событие drop (и да, я preventDefault()ed в dragover)

Я работаю над реализацией перетаскиваемых списков HTML5 и сталкиваюсь с проблемами.

По сути, всякий раз, когда я перетаскиваю элемент, я вставляю перетаскиваемый элемент непосредственно перед или после только что введенного элемента. Это означает, что когда вы перемещаете мышь, элемент продолжает перемещаться в положение под мышью. (Я установил visibility: hidden для элемента, поэтому он отображается как пустое место.) Когда вы отбрасываете элемент, я затем отправляю вызов AJAX на сервер, описывающий позицию элемента, чтобы выполнить перемещение на сервере.

Проблема в том, что по какой-то причине событие drop никогда не срабатывает (точка останова в моем обработчике никогда не срабатывает), а изображение перетаскивания возвращается туда, где оно началось. (Конечно, элемент переместился на странице, поэтому он снова появляется в своем новом местоположении, но поскольку drop никогда не срабатывает, сервер никогда не уведомляется об изменении.) Кто-нибудь знает, что происходит? Обычный ответ: "вам нужно вызвать preventDefault() в dragenter/dragover", но я уже это делаю.

Я использую jQuery 1.10.2 и вижу такое поведение как в Safari 7.0.1, так и в Firefox 26.0. Что бы это ни стоило, Rails 4.0.2 является моей основой для этого проекта, и я использую jquery_ujs и turbolinks.

Соответствующий код:

var draggingLI;

$('ol[data-passage-id]').find('li > a').attr('draggable', 'true')
.on('dragstart', function (ev) {
    draggingLI = $(ev.target).closest("li")[0];

    ev.originalEvent.dataTransfer.effectAllowed = 'move';
    ev.originalEvent.dataTransfer.setData('text/plain', ev.target.href);
    ev.originalEvent.dataTransfer.setData('text/uri-list', ev.target.href);
})
.on('dragenter', function (ev) {
    ev.originalEvent.dataTransfer.dropEffect = 'move'; 
    $(draggingLI).css('visibility', 'hidden');

    if(canDropIn(ev.target)) {
        var droppingLI = $(ev.target).closest("li")[0];

        if(draggingLI == droppingLI) {
            // do nothing
        }
        if(draggingLI.nextElementSibling == droppingLI) {
            // We want to move the dragging element below this element.
            $(droppingLI).after(draggingLI);
        }
        else {
            // We want to move the dragging element above this element.
            $(droppingLI).before(draggingLI);
        }

        ev.preventDefault();
        ev.stopPropagation();
        return false;
    }
})
.on('dragover', function (ev) {
    if(canDropIn(ev.target)) {
        ev.preventDefault();
        ev.stopPropagation();
        return false;
    }
})
.on('drop', function (ev) {
    sendMovedItem(draggingLI);
    ev.preventDefault();
    ev.stopPropagation();
    return false;
})
.on('dragend', function (ev) {
    $(draggingLI).css('visibility', '');
});

canDropIn() в настоящее время является заглушкой, которая всегда возвращает true. sendMovedItem() — это функция, которая выполняет вызов AJAX. В консоли ошибок нет.


person Becca Royal-Gordon    schedule 04.01.2014    source источник


Ответы (1)


Проблема, кажется, вызвана моей стратегией перемещения самого элемента перетаскивания; Я не уверен, связано ли это с тем, что перемещение элемента во время его перетаскивания вызывает проблемы с браузерами, или с тем, что перетаскивание исходного элемента не разрешено. Я работал над этим, полностью скрывая исходный элемент, а затем вставляя элемент-заполнитель, который я мог перемещать вместо него. (Вы должны прикрепить обработчики dragenter/dragover/drop к заполнителю, так как все успешные перетаскивания заканчиваются на заполнителе.)

Я бы все же предпочел решение, которое не требует заполнителя, если у кого-то есть идея!

person Becca Royal-Gordon    schedule 04.01.2014