//
// new SortingTable( 'my_table', {
// zebra: true, // Stripe the table, also on initialize
// details: false, // Has details every other row
// paginator: false, // Pass a paginator object
// onSorted: function(){}, // Callback to run after sort
// dont_sort_class: 'nosort', // Class name on th's that don't sort
// forward_sort_class: 'forward_sort', // Class applied to forward sort th's
// reverse_sort_class: 'reverse_sort' // Class applied to reverse sort th's
// });
//
// The above were the defaults. The regexes in load_conversions test a cell
// begin sorted for a match, then use that conversion for all elements on that
// column.
//
// Requires mootools Class, Array, Function, Element, Element.Selectors,
// Element.Event, and you should probably get Window.DomReady if you're smart.
//
var SortingTable = new Class({
Implements: [Options, Events],
options: {
zebra: true,
details: false,
paginator: false,
onSorted: $empty,
dont_sort_class: 'nosort',
forward_sort_class: 'forward_sort',
reverse_sort_class: 'reverse_sort'
},
initialize: function( table, options ) {
this.table = $(table);
this.setOptions(options);
this.tbody = this.table.getElement('tbody');
if (this.options.zebra) {
SortingTable.stripe_table(this.tbody.getChildren());
}
this.headers = this.table.getElement('thead').getElements('th');
this.headers.each(function( header, index ) {
if (header.hasClass( this.options.dont_sort_class )) { return }
header.store( 'column', index )
header.addEvent( 'mousedown', function(evt){
this.sort_by_header( evt.target );
if ( this.options.paginator) this.options.paginator.to_page( 1 );
}.bind( this ) );
}, this);
this.load_conversions();
},
sort_by_header: function( header ){
var rows = [];
var before = this.tbody.getPrevious();
this.tbody.dispose();
var trs = this.tbody.getChildren();
while ( row = trs.shift() ) {
row = { row: row.dispose() };
if ( this.options.details ) {
row.detail = trs.shift().dispose();
}
rows.unshift( row );
}
if ( this.sort_column >= 0 &&
this.sort_column == header.retrieve('column') ) {
// They were pulled off in reverse
if ( header.hasClass( this.options.reverse_sort_class ) ) {
header.removeClass( this.options.reverse_sort_class );
header.addClass( this.options.forward_sort_class );
} else {
header.removeClass( this.options.forward_sort_class );
header.addClass( this.options.reverse_sort_class );
}
} else {
this.headers.each(function(h){
h.removeClass( this.options.forward_sort_class );
h.removeClass( this.options.reverse_sort_class );
}, this);
this.sort_column = header.retrieve('column');
if (header.retrieve('conversion_function')) {
this.conversion_matcher = header.retrieve('conversion_matcher');
this.conversion_function = header.retrieve('conversion_function');
} else {
this.conversion_function = false;
rows.some(function(row){
var to_match = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
if (to_match == '') return false;
this.conversions.some(function(conversion){
if (conversion.matcher.test( to_match )){
this.conversion_matcher = conversion.matcher;
this.conversion_function = conversion.conversion_function;
return true;
}
return false;
}, this);
return !!(this.conversion_function);
}, this);
header.store('conversion_function', this.conversion_function );
header.store('conversion_matcher', this.conversion_matcher );
}
header.addClass( this.options.forward_sort_class );
rows.each(function(row){
var compare_value = this.conversion_function( row );
row.toString = function(){
return compare_value;
};
}, this);
rows.sort();
}
var index = 0;
while ( row = rows.shift() ) {
this.tbody.appendChild(row.row);
if (row.detail) this.tbody.appendChild(row.detail);
if ( this.options.zebra ) {
row.row.className = row.row.className.replace( this.removeAltClassRe, '$1').clean();
if (row.detail)
row.detail.className = row.detail.className.replace( this.removeAltClassRe, '$1').clean();
if (index % 2) {
row.row.addClass( 'alt' );
if (row.detail) row.detail.addClass( 'alt' );
}
}
index++;
}
this.tbody.inject(before, 'after');
this.fireEvent('sorted', this);
},
load_conversions: function() {
this.conversions = $A([
// 1.75 MB, 301 GB, 34 KB, 8 TB
{ matcher: /([0-9.]{1,8}).*([KMGT]{1})B/,
conversion_function: function( row ) {
var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
cell = this.conversion_matcher.exec( cell );
if (!cell) { return '0' }
if (cell[2] == 'M') {
sort_val = '1';
} else if (cell[2] == 'G') {
sort_val = '2';
} else if (cell[2] == 'T') {
sort_val = '3';
} else {
sort_val = '0';
}
var i = cell[1].indexOf('.')
if (i == -1) {
post = '00'
} else {
var dec = cell[1].split('.');
cell[1] = dec[0];
post = dec[1].concat('00'.substr(0,2-dec[1].length));
}
return sort_val.concat('00000000'.substr(0,2-cell[1].length).concat(cell[1])).concat(post);
}
},
// 1 day ago, 4 days ago, 38 years ago, 1 month ago
{ matcher: /(\d{1,2}) (.{3,6}) ago/,
conversion_function: function( row ) {
var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
cell = this.conversion_matcher.exec( cell );
if (!cell) { return '0' }
var sort_val;
if (cell[2].indexOf('month') != -1) {
sort_val = '1';
} else if (cell[2].indexOf('year') != -1) {
sort_val = '2';
} else {
sort_val = '0';
}
return sort_val.concat('00'.substr(0,2-cell[1].length).concat(cell[1]));
}
},
// Currency
{ matcher: /((\d{1}\.\d{2}|\d{2}\.\d{2}|\d{3}\.\d{2}|\d{4}\.\d{2}|\d{5}\.\d{2}|\d{6}\.\d{2}))/,
conversion_function: function( row ) {
var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
cell = cell.replace(/[^\d]/g, "");
return '00000000000000000000000000000000'.substr(0,32-cell.length).concat(cell);
}
},
// YYYY-MM-DD, YYYY-m-d
{ matcher: /(\d{4})-(\d{1,2})-(\d{1,2})/,
conversion_function: function( row ) {
var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
cell = this.conversion_matcher.exec( cell );
return cell[1]+
'00'.substr(0,2-cell[2].length).concat(cell[2])+
'00'.substr(0,2-cell[3].length).concat(cell[3]);
}
},
// Numbers
{ matcher: /^\d+$/,
conversion_function: function( row ) {
var cell = $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
return '00000000000000000000000000000000'.substr(0,32-cell.length).concat(cell);
}
},
// Fallback
{ matcher: /.*/,
conversion_function: function( row ) {
return $(row.row.getElementsByTagName('td')[this.sort_column]).get('text');
}
}
]);
}
});
SortingTable.removeAltClassRe = new RegExp('(^|\\s)alt(?:\\s|$)');
SortingTable.implement({ removeAltClassRe: SortingTable.removeAltClassRe });
SortingTable.stripe_table = function ( tr_elements ) {
var counter = 0;
tr_elements.each( function( tr ) {
if ( !tr.hasClass('collapsed') ) counter++;
tr.className = tr.className.replace( this.removeAltClassRe, '$1').clean();
if (counter % 2) tr.addClass( 'alt' );
});
}