-
Old school drag and drop
+
+
+
+
Introduction
+
+ Drag and drop is one of the most fundamental interactions
+ afforded by graphical user interfaces. In one gesture, it
+ allows users to pair the selection of an object with the
+ execution of an action, often including a second object in the
+ operation. It's a simple yet powerful UI concept used to
+ support copying, list reordering, deletion (ala the Trash / Recycle Bin),
+ and even the creation of link relationships.
+
+ Since it's so fundamental, offering drag and drop in web
+ applications has been a no-brainer ever since browsers first
+ offered mouse events in DHTML. But, although
+ mousedown
, mousemove
, and
+ mouseup
made it possible, the implementation has been
+ limited to the bounds of the browser window. Additionally,
+ since these events refer only to the object being dragged,
+ there's a challenge to find the subject of the drop when
+ the interaction is completed.
+
+ Of course, that doesn't prevent most modern JavaScript
+ frameworks from abstracting away most of the problems and
+ throwing in some flourishes while they're at it. But, wouldn't
+ it be nice if browsers offered first-class support for drag and
+ drop, and maybe even extended it beyond the window sandbox?
+
+ As it turns out, this very wish is answered by the HTML 5 specification
+ section on new drag-and-drop events, and
+ Firefox 3.5 includes an implementation of those events.
+
+ If you want to jump straight to the code, I've put together
+ some simple demos
+ of the new events.
+
+ I've even scratched an itch of my own and
+ built the beginnings of an outline editor,
+ where every draggable element is also a drop target—of which
+ there could be dozens to hundreds in a complex document, something
+ that gave me some minor hair-tearing moments at times in the past
+ while trying to make do with plain old mouse events.
+
+
+
+
The New Drag and Drop Events
+
So, with no further ado, here are the new drag and drop events:
+
+ dragstart
+ -
+ A drag has been initiated, with the dragged element as the
+ event target.
+
+ drag
+ -
+ The mouse has moved, with the dragged element as the event target.
+
+ dragenter
+ -
+ The dragged element has been moved into a drop listener,
+ with the drop listener element as the event target.
+
+ dragover
+ -
+ The dragged element has been moved over a drop listener,
+ with the drop listener element as the event target. Since
+ the default behavior is to cancel drops, returning
+
false
or calling preventDefault()
in
+ the event handler indicates that a drop is allowed here.
+
+ dragleave
+ -
+ The dragged element has been moved out of a drop listener,
+ with the drop listener element as the event target.
+
+ drop
+ -
+ The dragged element has been successfully dropped on a drop
+ listener, with the drop listener element as the event
+ target.
+
+ dragend
+ -
+ A drag has been ended, successfully or not, with the
+ dragged element as the event target.
+
+
+
+ Like mouse events and others, listeners can be attached to
+ elements for them with addEventListener()
+ directly or via your favorite JS library.
+
+ Consider the following example using jQuery, also available as
+ a demo:
+
+
+ <div id="newschool">
+ <div class="dragme">Drag me!</div>
+ <div class="drophere">Drop here!</div>
+ </div>
+
+ <script type="text/javascript">
+ $(document).ready(function() {
+ $('#newschool .dragme')
+ .attr('draggable', 'true')
+ .bind('dragstart', function(ev) {
+ var dt = ev.originalEvent.dataTransfer;
+ dt.setData("Text", "Dropped in zone!");
+ return true;
+ })
+ .bind('dragend', function(ev) {
+ return false;
+ });
+ $('#newschool .drophere')
+ .bind('dragenter', function(ev) {
+ $(ev.target).addClass('dragover');
+ return false;
+ })
+ .bind('dragleave', function(ev) {
+ $(ev.target).removeClass('dragover');
+ return false;
+ })
+ .bind('dragover', function(ev) {
+ return false;
+ })
+ .bind('drop', function(ev) {
+ var dt = ev.originalEvent.dataTransfer;
+ alert(dt.getData('Text'));
+ return false;
+ });
+ });
+ </script>
+
+
- This first demo isn't anything new at all—in fact, it's a really
- cruddy implementation of drag & drop using pre-3.5 mouse
- events.
-
-
-
-
Drag me!
-
Drop here!
-
-
-
-
-
-
-
-
New school drag and drop
-
-
Drag me!
-
Drop here!
-
-
-
-
-
-
-
New school drag and drop, now with Event Delegation!
-
-
-
-
-
-
Using drag feedback images
-
-
- - Drag 0
- - Drag 1
- - Drag 2
- - Drag 3
-
-
Drop here!
-
-
-
-
-
-
-
Using data transfer content types
-
-
-
- Drop here from items on the left—and selected
- content from other windows and applications.
-
-
- URL content appears here:
-
-
-
- Text content appears here:
-
-
-
- HTML content appears here:
-
-
-
-
-
-
-
-
-
-
Using drag effects
-
-
- - Drag 0 (copy)
- - Drag 1 (move)
- - Drag 2 (link)
- - Drag 3 (all)
- - Drag 4 (none)
-
-
- - Drop 0 (copy)
- - Drop 1 (move)
- - Drop 2 (link)
- - Drop 3 (all)
- - Drop 4 (none)
-
-
-
-
-
-
+
+
Using Drag Feedback Images
+
+
+
Using Drop Effects
+
diff --git a/js/drag-effects.js b/js/drag-effects.js
index eccc157..58db76d 100644
--- a/js/drag-effects.js
+++ b/js/drag-effects.js
@@ -27,30 +27,28 @@ $(document).ready(function() {
// Update the drop zone class on drag enter/leave
.bind('dragenter', function(ev) {
if (!$(ev.target).hasClass('drophere')) return true;
-
- var dt = ev.originalEvent.dataTransfer;
- switch (ev.target.id) {
- case 'effectdrop0': dt.dropEffect = 'copy'; break;
- case 'effectdrop1': dt.dropEffect = 'move'; break;
- case 'effectdrop2': dt.dropEffect = 'link'; break;
- case 'effectdrop3': dt.dropEffect = 'all'; break;
- case 'effectdrop4': dt.dropEffect = 'none'; break;
- }
-
$(ev.target).addClass('dragover');
return false;
})
.bind('dragleave', function(ev) {
if (!$(ev.target).hasClass('drophere')) return true;
-
$(ev.target).removeClass('dragover');
return false;
})
- // Allow drops of any kind into the zone.
+ // Allow only drops of the appropriate kind here
.bind('dragover', function(ev) {
if (!$(ev.target).hasClass('drophere')) return true;
+ var dt = ev.originalEvent.dataTransfer;
+ switch (ev.target.id) {
+ case 'effectdrop0': dt.dropEffect = 'copy'; break;
+ case 'effectdrop1': dt.dropEffect = 'move'; break;
+ case 'effectdrop2': dt.dropEffect = 'link'; break;
+ case 'effectdrop3': dt.dropEffect = 'all'; break;
+ case 'effectdrop4': dt.dropEffect = 'none'; break;
+ }
+
return false;
})
diff --git a/outline.html b/outline.html
index 8423d62..a5ddcbd 100644
--- a/outline.html
+++ b/outline.html
@@ -29,9 +29,10 @@
- Try reordering the outline items below by dragging them into new positions.
- - Try dragging in content selected from other web pages and applications.
+ - Try dragging in content selected from other browser windows and even other applications.
+ - View the JS code.
-
Back to the Drag & Drop demos
+
Back to the Drag & Drop demos