app/assets/javascripts/voluntary/lib/jquery.multisortable.js
/**
* jquery.multisortable.js - v0.2
* https://github.com/shvetsgroup/jquery.multisortable
*
* Author: Ethan Atlakson, Jay Hayes, Gabriel Such, Alexander Shvets
* Last Revision 3/16/2012
* multi-selectable, multi-sortable jQuery plugin
*/
!function($) {
$.fn.multiselectable = function(options) {
if (!options) {
options = {}
}
options = $.extend({}, $.fn.multiselectable.defaults, options);
function mouseDown(e) {
var item = $(this),
parent = item.parent(),
myIndex = item.index();
var prev = parent.find('.multiselectable-previous');
// If no previous selection found, start selecting from first selected item.
prev = prev.length ? prev : $(parent.find('.' + options.selectedClass)[0]).addClass('multiselectable-previous');
var prevIndex = prev.index();
if (e.ctrlKey || e.metaKey) {
if (item.hasClass(options.selectedClass)) {
item.removeClass(options.selectedClass).removeClass('multiselectable-previous')
if (item.not('.child').length) {
item.nextUntil(':not(.child)').removeClass(options.selectedClass);
}
}
else {
parent.find('.multiselectable-previous').removeClass('multiselectable-previous');
item.addClass(options.selectedClass).addClass('multiselectable-previous')
if (item.not('.child').length) {
item.nextUntil(':not(.child)').addClass(options.selectedClass);
}
}
}
if (e.shiftKey) {
var last_shift_range = parent.find('.multiselectable-shift');
last_shift_range.removeClass(options.selectedClass).removeClass('multiselectable-shift');
var shift_range;
if (prevIndex < myIndex) {
shift_range = item.prevUntil('.multiselectable-previous').add(prev).add(item);
}
else if (prevIndex > myIndex) {
shift_range = item.nextUntil('.multiselectable-previous').add(prev).add(item);
}
shift_range.addClass(options.selectedClass).addClass('multiselectable-shift');
}
else {
parent.find('.multiselectable-shift').removeClass('multiselectable-shift');
}
if (!e.ctrlKey && !e.metaKey && !e.shiftKey) {
parent.find('.multiselectable-previous').removeClass('multiselectable-previous');
if (!item.hasClass(options.selectedClass)) {
parent.find('.' + options.selectedClass).removeClass(options.selectedClass);
item.addClass(options.selectedClass).addClass('multiselectable-previous');
if (item.not('.child').length) {
item.nextUntil(':not(.child)').addClass(options.selectedClass);
}
}
}
options.mousedown(e, item);
}
function click(e) {
if ( $(this).is('.ui-draggable-dragging') ) {
return;
}
var item = $(this), parent = item.parent();
// If item wasn't draged and is not multiselected, it should reset selection for other items.
if (!e.ctrlKey && !e.metaKey && !e.shiftKey) {
parent.find('.multiselectable-previous').removeClass('multiselectable-previous');
parent.find('.' + options.selectedClass).removeClass(options.selectedClass);
item.addClass(options.selectedClass).addClass('multiselectable-previous');
if (item.not('.child').length) {
item.nextUntil(':not(.child)').addClass(options.selectedClass);
}
}
options.click(e, item);
}
return this.each(function() {
var list = $(this);
if (!list.data('multiselectable')) {
list.data('multiselectable', true)
.delegate(options.items, 'mousedown', mouseDown)
.delegate(options.items, 'click', click)
.disableSelection();
}
})
};
$.fn.multiselectable.defaults = {
click: function(event, elem) {},
mousedown: function(event, elem) {},
selectedClass: 'selected',
items: 'li'
};
$.fn.multisortable = function(options) {
if (!options) {
options = {}
}
var settings = $.extend({}, $.fn.multisortable.defaults, options);
function regroup(item, list) {
if (list.find('.' + settings.selectedClass).length > 0) {
var myIndex = item.data('i');
var itemsBefore = list.find('.' + settings.selectedClass).filter(function() {
return $(this).data('i') < myIndex
}).css({
position: '',
width: '',
left: '',
top: '',
zIndex: ''
});
item.before(itemsBefore);
var itemsAfter = list.find('.' + settings.selectedClass).filter(function() {
return $(this).data('i') > myIndex
}).css({
position: '',
width: '',
left: '',
top: '',
zIndex: ''
});
item.after(itemsAfter);
setTimeout(function() {
itemsAfter.add(itemsBefore).addClass(settings.selectedClass);
}, 0);
}
}
return this.each(function() {
var list = $(this);
//enable multi-selection
list.multiselectable({
selectedClass: settings.selectedClass,
click: settings.click,
items: settings.items,
mousedown: settings.mousedown
});
//enable sorting
options.cancel = settings.items + ':not(.' + settings.selectedClass + ')';
options.placeholder = settings.placeholder;
options.start = function(event, ui) {
if (ui.item.hasClass(settings.selectedClass)) {
var parent = ui.item.parent();
//assign indexes to all selected items
parent.find('.' + settings.selectedClass).each(function(i) {
$(this).data('i', i);
});
// adjust placeholder size to be size of items
var height = parent.find('.' + settings.selectedClass).length * ui.item.outerHeight();
ui.placeholder.height(height);
}
settings.start(event, ui);
};
options.stop = function(event, ui) {
regroup(ui.item, ui.item.parent());
settings.stop(event, ui);
};
options.sort = function(event, ui) {
var parent = ui.item.parent(),
myIndex = ui.item.data('i'),
top = parseInt(ui.item.css('top').replace('px', '')),
left = parseInt(ui.item.css('left').replace('px', ''));
// fix to keep compatibility using prototype.js and jquery together
$.fn.reverse = Array.prototype._reverse || Array.prototype.reverse
var height = 0;
$('.' + settings.selectedClass, parent).filter(function() {
return $(this).data('i') < myIndex;
}).reverse().each(function() {
height += $(this).outerHeight();
$(this).css({
left: left,
top: top - height,
position: 'absolute',
zIndex: 1000,
width: ui.item.width()
})
});
height = ui.item.outerHeight();
$('.' + settings.selectedClass, parent).filter(function() {
return $(this).data('i') > myIndex;
}).each(function() {
var item = $(this);
item.css({
left: left,
top: top + height,
position: 'absolute',
zIndex: 1000,
width: ui.item.width()
});
height += item.outerHeight();
});
settings.sort(event, ui);
};
options.receive = function(event, ui) {
regroup(ui.item, ui.sender);
settings.receive(event, ui);
};
list.sortable(options).disableSelection();
})
};
$.fn.multisortable.defaults = {
start: function(event, ui) {},
stop: function(event, ui) {},
sort: function(event, ui) {},
receive: function(event, ui) {},
click: function(event, elem) {},
mousedown: function(event, elem) {},
selectedClass: 'selected',
placeholder: 'placeholder',
items: 'li'
};
}(jQuery);