Skip to content

Instantly share code, notes, and snippets.

@ixtli
Last active August 29, 2015 14:14
Show Gist options
  • Save ixtli/4baed07ab212dcb573f0 to your computer and use it in GitHub Desktop.
Save ixtli/4baed07ab212dcb573f0 to your computer and use it in GitHub Desktop.
ember mixin
import Ember from 'ember';
var $ = Ember.$;
// These are defined in reorder-handle.scss
var DRAGGING_CLASS = 'is-dragging';
var DRAG_OVER_CLASS = 'drag-over';
var DROP_TARGET_CLASS = 'drop-target';
/**
* Handles dragover from other syblings
*/
function _siblingDragOver(event)
{
$(this).addClass(DRAG_OVER_CLASS);
// If you dont do this, the drop event doesnt get called.
event.preventDefault();
return false;
}
/**
* Mark the recieving row as the drop target
*/
function _siblingDrop(event)
{
$(this).addClass(DROP_TARGET_CLASS);
event.preventDefault();
return false;
}
/**
* Handles the dragleave from other syblings
*/
function _siblingDragLeave(event)
{
$(this).removeClass(DRAG_OVER_CLASS);
}
/**
* This swaps two elements in a HasMany collection. The normal way you'd do it
* with an ember mutable array doesnt work because ember data poorly documents
* its additions to the class it extends to implement hasMany.
*/
function _swapCollectionElements(collection, first, second)
{
var firstObject = collection.objectAt(first);
var secondObject = collection.objectAt(second);
collection.removeObject(firstObject);
collection.removeObject(secondObject);
if (first < second)
{
collection.insertAt(first, secondObject);
collection.insertAt(second, firstObject);
} else {
collection.insertAt(second, firstObject);
collection.insertAt(first, secondObject);
}
}
export default Ember.Mixin.create({
// The collection of objects that the container value belongs to.
// Records are reorderd within the container when something is dropped
reorderCollection: null,
dragStart: function(event)
{
var self = $(event.target);
// This implementation assumes that the element being reordered is the
// PARENT of the UI element that initiates the dragging. I find this to
// be a more consistent user experience otherwise the user may accidentally
// initiate row dragging by clicking somewhere else.
var parent = self.parent();
parent.addClass(DRAGGING_CLASS);
// Assume here that all other elements at the same level as the parent
// are sortable elements. This tells them to respond to dragover.
var siblings = parent.siblings();
siblings.on('dragover.clg', _siblingDragOver);
siblings.on('dragleave.clg', _siblingDragLeave);
siblings.on('drop.clg', _siblingDrop);
},
dragEnd: function(event)
{
var self = $(event.target);
// Clean up the dragged element
var parent = self.parent();
parent.removeClass(DRAGGING_CLASS);
// The row container
var container = parent.parent();
var over = container.children('.' + DROP_TARGET_CLASS);
// Clear the drag-over handler and state
var siblings = parent.siblings();
siblings.removeClass(DRAG_OVER_CLASS);
siblings.off('dragover.clg');
siblings.off('dragleave.clg');
siblings.off('drop.clg');
if (!over.length)
{
return;
}
// Check to make sure the embedder has defined a collection
var collection = this.get('reorderCollection');
if (!collection)
{
console.warn('No reorder collection defined.');
return;
}
// Swap elements
_swapCollectionElements(collection, parent.index(), over.index());
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment