Skip to content

Instantly share code, notes, and snippets.

@garyhodgson
Forked from jashkenas/DropManager.js
Created October 8, 2009 22:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save garyhodgson/205455 to your computer and use it in GitHub Desktop.
Save garyhodgson/205455 to your computer and use it in GitHub Desktop.
// This code is MIT licensed: http://creativecommons.org/licenses/MIT/
// Zenbe Inc (2009).
// Ensure our Zenbe namespaces exist.
window.zen = window.zen || {};
window.zen.util = window.zen.util || {};
/**
* The DropManager class provides a pleasant API for observing HTML5 drag-n-drop
* events, cleaning up the data that they return, and triggering the appropriate
* callbacks. With the drag and drop API so far, there are generally three types
* of data we're interested in: HTML, URLs, and plain text. On drop, your
* callback will receive a pre-processed drop object with corresponding 'url',
* 'html' and 'text' properties.
*
* To use it, instantiate a new DropManager, passing in an element to use as a
* drop target, as well as an (optional) callbacks object, with (optional)
* callbacks for drop, dragenter, dragover and dragleave:
*
* new zen.util.DropManager($('drop_target'), {
* drop : function(event, dropData) { ... process data here ... }
* });
*
*/
window.zen.util.DropManager = Class.create({
SUPPORTED_TYPES : ['text/uri-list', 'text/x-moz-url', 'text/html',
'text/plain', 'Url', 'Text'],
IMAGE_LINK_DETECTOR : (/^\s*<a.+?<img.+?src=['"](\S+?)['"].*?>\s*<\/a>\s*$/i),
URL_DETECTOR : (/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/),
/**
* Registers all of the drop handlers that we'll need for dealing with
* drop-related actions on the target element.
*/
initialize : function(element, callbacks) {
this.enabled = true;
this.callbacks = callbacks || {};
this.el = element;
this.el.observe('dragenter', this._boundDragEnter = this._onDragEnter.bind(this));
this.el.observe('dragover', this._boundDragOver = this._onDragOver.bind(this));
this.el.observe('dragleave', this._boundDragLeave = this._onDragLeave.bind(this));
this.el.observe('drop', this._boundDrop = this._onDrop.bind(this));
},
/**
* Removes all of the drop handlers from the target element.
*/
destroy : function() {
this.el.stopObserving('dragenter', this._boundDragEnter);
this.el.stopObserving('dragover', this._boundDragOver);
this.el.stopObserving('dragleave', this._boundDragLeave);
this.el.stopObserving('drop', this._boundDrop);
},
/**
* Turn the DropManager's callbacks on and off. If disabled, none of your
* passed-in callbacks will be fired until the DropManager is re-enabled.
*/
setEnabled : function(enabled) {
this.enabled = enabled;
},
/**
* Does the DropManager support the drop event? Returns true if we're enabled,
* and we support at least one of the drop's mime types.
* @function ?
*/
supports : function(ev) {
if (!this.enabled) return false;
var types = $A(ev.dataTransfer.types);
if (!types.any()) return true; // IE doesn't give us any types whatsoever.
return this.SUPPORTED_TYPES.any(function(t){ return types.include(t); });
},
/**
* Internal function to post-process the drop data to pull out HTML image links
* (<a><img></a>). The desired url is probably for the image, not the link.
* In addition, some versions of webkit pass perfectly good urls as just
* text/plain -- pull 'em out.
*/
_postProcess : function(data) {
var textPart = data.html || data.text;
var match = textPart && textPart.match(this.IMAGE_LINK_DETECTOR);
if (match) data.url = match[1];
match = data.text && !data.url && data.text.match(this.URL_DETECTOR);
if (match) data.url = data.text;
return data;
},
/**
* On drop, we pull out our preferred and supported mime-types, process them
* for links, and return the resulting drop object to the provided callback.
* @function ?
*/
_onDrop : function(ev) {
ev.preventDefault();
if (!this.supports(ev)) return false;
var dt = ev.dataTransfer;
try {
var data = {
url : dt.getData('text/uri-list') || dt.getData('text/x-moz-url'),
html : dt.getData('text/html').stripScripts(),
text : dt.getData('text/plain')
};
} catch(e) { // IE doesn't support mime types yet.
var data = {
url : dt.getData('Url'),
text : dt.getData('Text')
};
}
data = this._postProcess(data);
if (this.callbacks.drop) this.callbacks.drop(ev, data);
},
/**
* On drag enter, enable dropping on the drop target.
* @function ?
*/
_onDragEnter : function(ev) {
ev.preventDefault();
if (!this.supports(ev)) return false;
try { // IE Doesn't allow this property to be set ... but Webkit requires it.
ev.dataTransfer.effectAllowed = 'all';
ev.dataTransfer.dropEffect = 'copy';
} catch(e){}
if (this.callbacks.dragenter) this.callbacks.dragenter(ev);
},
/**
* On drag over, enable dropping on the drop target.
* @function ?
*/
_onDragOver : function(ev) {
ev.preventDefault();
if (!this.supports(ev)) return false;
try { // IE Doesn't allow this property to be set ... but Webkit requires it.
ev.dataTransfer.effectAllowed = 'all';
ev.dataTransfer.dropEffect = 'copy';
} catch(e){}
if (this.callbacks.dragover) this.callbacks.dragover(ev);
},
/**
* Not much to do for drag leave.
* @function ?
*/
_onDragLeave : function(ev) {
ev.preventDefault();
if (!this.supports(ev)) return false;
if (this.callbacks.dragleave) this.callbacks.dragleave(ev);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment