При запуске Firefox при запуске

Я пытаюсь отслеживать dragenter/leave для всего экрана, который до сих пор отлично работает в Chrome/Safari, благодаря плану draguover из qaru.site/info/33623/... как в:

$.fn.draghover = function(options) {
    return this.each(function() {

        var collection = $(),
            self = $(this);

        self.on('dragenter', function(e) {
            if (collection.size() === 0) {
                self.trigger('draghoverstart');
            }
            collection = collection.add(e.target);
        });

        self.on('dragleave drop', function(e) {
            // timeout is needed because Firefox 3.6 fires the dragleave event on
            // the previous element before firing dragenter on the next one
            setTimeout( function() {
                collection = collection.not(e.target);
                if (collection.size() === 0) {
                    self.trigger('draghoverend');
                }
            }, 1);
        });
    });
};

function setText(text) {
    $('p.target').text(text);
}

$(document).ready(function() {
    $(window).draghover().on({
        'draghoverstart': function() {
            setText('enter');
        },
        'draghoverend': function() {
            setText('leave');
        }
    });
});

Однако Firefox по-прежнему создает проблемы при перетаскивании текстовых элементов, вот скрипка, демонстрирующая: http://jsfiddle.net/tusRy/6/

Является ли это ошибкой Firefox или ее можно приручить JS? Или существует более надежный способ выполнения всего этого?

Спасибо!

UPDATE: обновить скрипт до http://jsfiddle.net/tusRy/6/, чтобы немного уменьшить беспорядок. Чтобы объяснить ожидаемое поведение скрипта:

  • Перетащите файл в окно, а p.target должен быть "ENTER" цветным.
  • Извлеките файл из окна, а p.target должен "ОСТАВИТЬ" цветной красный.
  • Отбросьте файл в окне, а p.target должен "ОСТАВИТЬ" цветной красный.

В firefox событие LEAVE запускается при перетаскивании файла по тексту.

Ответ 1

С версии 22.0 Firefox все еще это делает. Когда вы перетаскиваете текст node, он запускает два вида событий dragenter и dragleave: один, где целевой объект и связанный с ним таргетинг являются BOTH родительским элементом текста node, а другой, где цель является родительской элемент, а связанный с ним Target - это фактический текст node (даже не соответствующий элемент DOM).

Обходной путь - это просто проверить эти два вида событий в обработчиках dragenter и dragleave и игнорировать их:

try {
    if(event.relatedTarget.nodeType == 3) return;
} catch(err) {}
if(event.target === event.relatedTarget) return;

Я использую блок try/catch для проверки nodeType, потому что из-за непредвиденных событий события (необъяснимо) из-за пределов документа (например, в других iframe) и попытки доступа к их узлуType вызывают ошибку разрешений.

Здесь реализация: http://jsfiddle.net/9A7te/

Ответ 2

Я придумал какое-то решение, но для тестирования других браузеров, кроме Chrome и FF, но работающих до сих пор. Вот как выглядит setTimeout:

setTimeout( function() {
    var isChild = false;

    // in order to get permission errors, use the try-catch
    // to check if the relatedTarget is a child of the body
    try {
        isChild = $('body').find(e.relatedTarget).length ? true : isChild;
    }
    catch(err){} // do nothing

    collection = collection.not(e.target);
    if (collection.size() === 0 && !isChild) {
        self.trigger('draghoverend');
    }
}, 1);

Весь код здесь - http://jsfiddle.net/tusRy/13/.

Идея состоит в том, чтобы проверить, является ли связанный тэг дочерним по отношению к телу, и в этом случае мы все еще находимся в Браузерах, а событие draghoverend не должно запускаться. Поскольку это может вызывать ошибки при перемещении из окон, я использовал метод try, чтобы избежать этого.

Ну, возможно, кто-то, у кого больше навыков в JS, может улучшить это:)

Ответ 3

1) Ваша dropzone должна иметь только один дочерний элемент, который может иметь все, что вам нужно. Что-то вроде

<div id="#dropzone">
    <div><!--Your contents here--></div>
</div>

2) Используйте этот CSS:

#dropzone * { pointer-events: none; }

Вам может потребоваться включить :before и :after, так как * не применимо к ним.

Этого должно быть достаточно, чтобы позволить работать в Firefox и Chrome. В вашем примере это должно быть достаточно, чтобы добавить:

body * { pointer-events: none; }

В конце CSS. Я сделал это здесь:

Другие примеры:

Ответ 4

Я нашел ответ в невыбранном ответе на этот вопрос SO, спрашивающий о стрельбах для включения дочерних элементов. У меня есть <div>, который содержит много дочерних элементов. Полупрозрачное наложение <span> становится видимым над <div>, если на странице есть dragenter. Как вы нашли, "dragover" не похож на mouseover. Он запускает dragleave всякий раз, когда вы наводите над дочерним элементом.

Решение? Dragout Он делает dragover более похожим на mouseover. Очень короткий.