Defines Fx.Sort, a class that reorders lists with a transition.
Fx.Sort = new Class({
Extends: Fx.Elements,
options: {
mode: 'vertical'
},
initialize: function(elements, options){
this.parent(elements, options);
this.elements.each(function(el){
if (el.getStyle('position') == 'static') el.setStyle('position', 'relative');
});
this.setDefaultOrder();
},
setDefaultOrder: function(){
this.currentOrder = this.elements.map(function(el, index){
return index;
});
},
sort: function(){
if (!this.check(arguments)) return this;
var newOrder = Array.flatten(arguments);
var top = 0,
left = 0,
next = {},
zero = {},
vert = this.options.mode == 'vertical';
var current = this.elements.map(function(el, index){
var size = el.getComputedSize({styles: ['border', 'padding', 'margin']});
var val;
if (vert){
val = {
top: top,
margin: size['margin-top'],
height: size.totalHeight
};
top += val.height - size['margin-top'];
} else {
val = {
left: left,
margin: size['margin-left'],
width: size.totalWidth
};
left += val.width;
}
var plane = vert ? 'top' : 'left';
zero[index] = {};
var start = el.getStyle(plane).toInt();
zero[index][plane] = start || 0;
return val;
}, this);
this.set(zero);
newOrder = newOrder.map(function(i){ return i.toInt(); });
if (newOrder.length != this.elements.length){
this.currentOrder.each(function(index){
if (!newOrder.contains(index)) newOrder.push(index);
});
if (newOrder.length > this.elements.length)
newOrder.splice(this.elements.length-1, newOrder.length - this.elements.length);
}
var margin = top = left = 0;
newOrder.each(function(item, index){
var newPos = {};
if (vert){
newPos.top = top - current[item].top - margin;
top += current[item].height;
} else {
newPos.left = left - current[item].left;
left += current[item].width;
}
margin = margin + current[item].margin;
next[item]=newPos;
}, this);
var mapped = {};
Array.clone(newOrder).sort().each(function(index){
mapped[index] = next[index];
});
this.start(mapped);
this.currentOrder = newOrder;
return this;
},
rearrangeDOM: function(newOrder){
newOrder = newOrder || this.currentOrder;
var parent = this.elements[0].getParent();
var rearranged = [];
this.elements.setStyle('opacity', 0);
move each element and store the new default order
newOrder.each(function(index){
rearranged.push(this.elements[index].inject(parent).setStyles({
top: 0,
left: 0
}));
}, this);
this.elements.setStyle('opacity', 1);
this.elements = $$(rearranged);
this.setDefaultOrder();
return this;
},
getDefaultOrder: function(){
return this.elements.map(function(el, index){
return index;
});
},
forward: function(){
return this.sort(this.getDefaultOrder());
},
backward: function(){
return this.sort(this.getDefaultOrder().reverse());
},
reverse: function(){
return this.sort(this.currentOrder.reverse());
},
sortByElements: function(elements){
return this.sort(elements.map(function(el){
return this.elements.indexOf(el);
}, this));
},
swap: function(one, two){
if (typeOf(one) == 'element') one = this.elements.indexOf(one);
if (typeOf(two) == 'element') two = this.elements.indexOf(two);
var newOrder = Array.clone(this.currentOrder);
newOrder[this.currentOrder.indexOf(one)] = two;
newOrder[this.currentOrder.indexOf(two)] = one;
return this.sort(newOrder);
}
});