Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Browser "drag and drop" events: Can anyone fill in the blanks?

I've never really had the need to use any drag functions until now, so let me fill you in on what I've discovered so far:

  • Drag events are events that take place when the user is dragging an object. This is "proper" OS dragging, eg: hiliting some text and dragging it, or even dragging in something from outside of the browser.
  • While dragging, as far as I can tell, no other browser events will be fired. (onmouseover is ignored, for example). The only events that work are drag events.
  • In all modern browsers, onDragEnter and onDragOver appear to work... but firefox lacks "onDragLeave."
  • For dropping, FF uses "onDragDrop" while IE and others use "onDrop" while Safari doesn't appear to support it.
  • Events only seem to work on "droppable" elements, like textarea and text. On other elements only some events work.
  • Various other quirks for each browser that I don't even want to go over.
  • There is very little documented about these events.

Yes, I must use actual drag+drop, and cannot simulate it.

My questions:

  • Is there a way to detect "ondragleave" or similar in FF?
  • Is there a way to detect "ondragdrop" or similar in Safari?
  • Do you have anything to add about Drag + Drop?

Here's a quick and dirty template demonstrating drag and drop events:

<script>
    addEvent = function(obj, eventname, fn){
        if (document.addEventListener) obj.addEventListener(eventname, fn, false);
        else obj.attachEvent('on'+eventname, fn);
    }

    window.onload = function(){
        var logger = document.getElementById("logger");
        var log = function(str){ logger.value = str + logger.value; }

        //log a variety of drag events for the textarea
        var obj = document.getElementById("tarea");
        var events = ["dragenter","dragover","dragout","dragleave","dragdrop","drop"];
        for (var i=0; i<events.length; i++){
            (function(event){//create a closure to remove variable scope
                addEvent(obj, event, function(){ log("textarea: " + event + "\n"); });
            })(events[i]);
        }

        //log events on the div
        obj = document.getElementById("div");
        events = ["mouseover","mouseout","mouseup","mousedown","click","dblclick",
                "dragenter","dragover","dragout","dragleave","dragdrop","drop"];
        for (var i=0; i<events.length; i++){
            (function(event){//create a closure to remove variable scope
                addEvent(obj, event, function(){ log("div: " + event + "\n"); });
            })(events[i]);
        }
    }
</script>
Life's a drag when doing cross browser stuff.<br><br>
<div id="div" style="width: 100px; height: 100px; background: green; float: left;">
</div>
<textarea id="tarea" style="width: 100px; height: 100px; float: left; margin: 0px 5px;">
</textarea>

<textarea id="logger" style="width: 200px; height: 400px; float: left;">
</textarea>
like image 918
sam Avatar asked Jan 26 '09 02:01

sam


1 Answers

I've found a way to handle onDragLeave via event delegation.

Simply add an event to monitor "dragover" on the entire document. When the event source becomes your element in question, set a flag, and once the event source is no longer that element, fire the "dragleave" event.

Note:

  • Will need to be modified so that "e.source==obj" is actually "obj.childOf(e.source)" ... since the source element may be a descendant of the object in question.
  • Requires the event handling framework to figure out what "source" is based on browser.

Unfortunately it looks like Safari's lack of "ondrop" cannot be fixed... it simply never gets fired.

How to achieve "dragleave" in FF (well, all browsers):

var setOnDragLeave = function(obj, fn){
    var on=false;
    var dragover = function(e){
        if (on){
            if (e.source!=obj){
                on = false;
                e.eventname = "dragleave";
                fn.call(obj, e);
            }
            return;
        }else{
            if (e.source==obj) on = true;
            return;
        }
    }
    addEvent(document.documentElement, "dragover", dragover);
}
setOnDragLeave(obj, function(e){ logEvent(e); });

I sincerely hope someone else on this planet can use this...

like image 135
sam Avatar answered Nov 09 '22 21:11

sam