Skip to content

Instantly share code, notes, and snippets.

@obeattie
Created September 5, 2011 11:33
Show Gist options
  • Save obeattie/1194755 to your computer and use it in GitHub Desktop.
Save obeattie/1194755 to your computer and use it in GitHub Desktop.
/* Draggable lists */
ul.reorderable {
position: relative;
z-index: 1;
border-top: 1px solid lighten(@mute, 10%);
border-bottom: 1px solid lighten(@mute, 10%);
li {
.unselectable;
position: relative;
display: block;
list-style: none;
padding: 5px 0;
border-top: 1px solid lighten(@mute, 10%);
border-bottom: 1px solid lighten(@mute, 10%);
cursor: move;
background: url('/media/img/moveable.png') right center no-repeat;
z-index: 2;
&:not(.clone) {
top: -1px;
margin-bottom: -1px;
}
&:last-child {
margin-bottom: -2px;
}
&.clone {
position: absolute;
background-color: rgba(255, 255, 255, .4);
z-index: 3;
left: 0;
right: 0;
}
&.dragging {
opacity: 0;
}
}
}
/* ----------
Reorderable lists, iPhone style
----------
*/
OB.ReorderableList = function(list, options){
_.bindAll(this);
this.list = $(list);
this._clonedItem = null;
this.options = _.extend({}, this.defaultOptions, (options || {}));
this.draw();
}
_.extend(OB.ReorderableList.prototype, Backbone.Events, {
defaultOptions: {},
startDrag: function(event){
var target = $(event.target).closest('li');
var clone = target.clone().addClass('clone');
// Update the position before inserting
this._cloneTarget = target;
this._clonedItem = clone;
this._originalIndex = this.list.children('li:not(.clone):not(.disposable)').index(target);
this._newIndex = null;
this.offset = (target.offset().top - 1 - event.clientY);
this.updateDrag(event);
// Insert into the DOM
target.addClass('dragging').closest('ul').prepend(clone);
// Bind updateDrag and endDrag to mousemove and mouseup, respectively
$(document.body).bind({
mousemove: this.updateDrag,
mouseup: this.endDrag
});
return false;
},
endDrag: function(event){
this._clonedItem.remove();
$('li.dragging', this.list).removeClass('dragging');
// Fire the change event
var newIndex = (this._newIndex !== null ? this._newIndex : this._originalIndex);
var moved = ((newIndex + 1) - (this._originalIndex + 1));
if (moved !== 0){
this.trigger('change', this._cloneTarget, moved);
}
// Unbind these as the drag is over
$(document.body).unbind({
mousemove: this.updateDrag,
mouseup: this.endDrag
});
return false;
},
updateDrag: function(event){
// Only do anything if the (x) is within the list
var topOffset = this.list.offset().top;
var bottomOffset = topOffset + this.list.height();
if (event.clientY >= topOffset && event.clientY <= bottomOffset){
// Reposition the clone
var pos = (this.offset + (event.clientY - topOffset));
this._clonedItem.css('top', pos);
// Now, figure out if the items need moving around
var x = (this.list.offset().left + (this.list.width() / 2));
this._clonedItem.hide();
var target = document.elementFromPoint(x, event.clientY);
this._clonedItem.show();
target = $(target);
if ((!target.is(this._cloneTarget)) &&
target.is('li') &&
target.closest('ul').is(this.list)
){
// Okay, so let's move it around
if (event.clientY < (target.offset().top + (target.outerHeight() / 2))){
this._cloneTarget.insertBefore(target);
} else {
this._cloneTarget.insertAfter(target);
}
this._newIndex = this.list.children('li:not(.clone):not(.disposable)').index(this._cloneTarget);
}
}
return false;
},
draw: function(){
$('li', this.list).live('mousedown', this.startDrag);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment