Who am I?
- Senior Developer at Seek
- Developer on Modernizr
-
Stalk me:
A bit of history
- Proprietary MS extension
- Was shipped in IE5 1999
- Became useful when the other browsers decided to ship it: FF3.5, Safar 3.1 and Chrome 4. No Opera :(
- Part of the HTML5 spec
- Not to be confused with all the fake drag and drop stuff out there
What makes an element draggable?
- Both img and anchor elements are naturally draggable
- Add the "draggable" attribute to any other element to give it the same behaviour
- Webkit requires some CSS to make it draggable
<div draggable="true">
Drag me
</div>
[draggable="true"] {
-khtml-user-drag: element;
-webkit-user-drag: element;
-khtml-user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
user-drag: element;
user-select: none;
}
What makes an element droppable?
- Input, textarea and contenteditable elements
- HTML5 spec has defined the "dropzone" attribute but no browser supports as of yet*
- When dropzone is supported the attribute will handle some cases
<div dropzone="copy f:image/*" ondrop="handleDrop(event, this)">
Drop here!
</div>
* I could be wrong, Chrome maybe?
dataTransfer
- On a DnD event you have event.dataTransfer
-
The dragstart event you can set some data using the setData() method
- Takes two arguments: type and data
- For cross browser goodness text/plain is your best bet
dataTransfer
-
ondrop event you can get the data using the getData() method
- Takes one argument of type
- Will return any data that was set to the same type in the dragstart event
Dropping
var dropzone = document.querySelector(".dropzone");
document.querySelector(".dragr").ondragstart = function(e) {
var dt = e.dataTransfer;
dt.setData("text/plain", "I got dropped");
}
dropzone.ondrop = function(e) {
var dt = e.dataTransfer,
elem = this;
elem.textContent = dt.getData("text/plain");
e.preventDefault();
}
dropzone.ondragenter = function(e){e.preventDefault();}
dropzone.ondragover = function(e){e.preventDefault();}
Rad use cases
-
Drag out a file and save it to your desktop
dragout.ondragstart = function(e) {
var dt = e.dataTransfer,
data = this.getAttribute("data-downloadurl");
dt.setData("DownloadURL", data);
}
<a href="assets/html5-cheat-sheet.pdf"
class="button dragout"
data-downloadurl="application/pdf:
HTML5CheatSheet.pdf:
http://ryanseddon.com/demo/gmail_dragout/html5-cheat-sheet.pdf"
>Drag me to your desktop</a>
Rad use cases
- font dragr bookmarklet font dragr
-
setData payload can be quite large e.g. 150kb no problems
- The bookmarklet captures the drop which passes in the font in base64 format and injects it into the page.
- It's just a JSON string which is parsed on drop and the font information is extracted
- Can pass from browser to browser
- IE will bork on any thing other than "Text" on the set/getData() methods
Can fix with conditional compilation to fork for IE @cc_on
Friends
- FileList interface
- File API
- create/revokeObjectURL
Friends: FileList interface
- Mozilla introduced file access through drop events in FF3.6
- Extended dataTransfer object with the files property
var fileaccess = document.querySelector(".fileaccess");
fileaccess.ondrop = function(e) {
var dt = e.dataTransfer, files = dt.files, elem = this;
elem.innerHTML = files[0].name + " " + files[0].size + " " + files[0].type;
e.preventDefault();
}
fileaccess.ondragenter = function(e){e.preventDefault();}
fileaccess.ondragover = function(e){e.preventDefault();}
Drop a file here
Friends: File API
- File API actually allows you to do something useful with the file
-
FileReader interface
- Async FileReader allows you to read the file into memory
- Various types readAsText/BinaryString/DataURL/ArrayBuffer
var dt = e.dataTransfer, files = dt.files, elem = this,
img = document.createElement("img"),
reader = new FileReader();
reader.onloadend = function(file) {
img.src = file.target.result;
elem.appendChild(img);
}
reader.readAsDataURL(files[0]);
Drop an image here
Friends: File API
- font dragr also works with font files from your filesystem
- Same goes for the font dragr bookmarklet in supporting browsers
Friends: create/revokeObjectURL
- Loading files into memory isn't very efficient
-
Bring in createObjectURL
- Instead of reading into memory this API creates a Blob URL
- Look something like this: blob:e5e2c02c-8f10-48e6-b31e-2fb751c3582b
- Works wherever URIs work on the web e.g. imgs, CSS etc
- Lives for the life of the document
var dt = e.dataTransfer, files = dt.files, elem = this,
url = url = window.URL || window.webkitURL;
elem.innerHTML = url.createObjectURL(files[0]);
Drop an file here to see blob URL
Other use cases
- Drag and drop image uploading
- A way around clipboard restrictions, see Chrome dev tools
- Contacts importing, drag in a .vcf file etc