views:

1192

answers:

5

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>
+3  A: 

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...

sam
A: 

Nice article. I too am looking for an equivalent of ondrop/ondragdrop in Safari. However, there is a possible workaround for "internal" drag-drop case, i.e. the drag source and drop target are in the same document.

IE supports the events ondragstart, ondrag and ondragend on the drag source element. Safari 3 fires these as well. Firefox3 fires ondrag and ondragend, but not ondragstart (though the documentation suggests that it should). Anyway, depending on your scenario, you may be able to use ondragend to detect when the drag-drop operation is completed.

A: 

This only supports dragging of text... how would you do this with images?

A: 

Firefox implements the "dragleave" event as "dragexit", it seems. Just learnt this now. And it works.

A: 

I too am looking for an equivalent of ondrop/ondragdrop in Safari.

Actually, here is an important note:

Note: You must, at minimum, implement ondragover and call the preventDefault method on the event object. If you do not do this, you will not receive any of these four (ondragenter, ondragover, ondragleave, ondrop) events.