//// 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// 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,	options : {		zebra : true,		details : false,		paginator : false,		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());		}				// KEP - Use headerRow option to indicate the <tr> in <thead> that should have sort controls.		this.headerRow = this.options.headerRow ? this.options.headerRow : 0;		if (this.options.headerRow == null) {			this.headers = this.table.getElement('thead').getElements('th');		} else {			this.headers = this.table.getElement('thead').getElements('tr')[this.options.headerRow].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);				this.sort_by_header(header);				if (this.options.paginator)					this.options.paginator.to_page(1);			}.bind(this));		}, this);		this.load_conversions();				if (this.options.preSort) this.sort_by_header(this.headers[this.options.preSort]);	},	sort_by_header : function(header) {		var rows = [];		var before = this.tbody.getPrevious();		this.tbody.dispose();		var trs = this.tbody.getChildren();		if (trs.length < 1) return false;		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) {									// In case table has no data cells									//var cells_to_match = row.row.getElementsByTagName('td')[this.sort_column];									//if (cells_to_match == null) return false;									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');	},	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]));					}				},				// KEP - Dates as used in the US - illogical though it may be.				// MM-DD-YYYY, m-d-YYYY				{					matcher : /\d{1,2}\/\d{1,2}\/\d{4}/,					conversion_function : function(row) {						var cell = $(row.row.getElementsByTagName('td')[this.sort_column])								.get ('text');						var re = /(\d{1,2})\/(\d{1,2})\/(\d{4})/;						cell = re.exec(cell);						return cell[3]+		                 '00'.substr(0,2-cell[1].length).concat(cell[1])+        		         '00'.substr(0,2-cell[2].length).concat(cell[2]);/* Found out this wasn't working all the time.						cell = new Date(parseInt(cell[3]), parseInt(cell[1]),								parseInt(cell[2]));														cell = cell.getTime();						cell = '00000000000000000000000000000000'.substr(0,								32 - cell.length).concat(cell);						return cell;*/					}				},								// 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 new Date(parseInt(cell[1]),								parseInt(cell[2], 10) - 1,								parseInt(cell[3], 10));					}				},				// KEP - Enhanced to support decimal values.				// Numbers				{					matcher : /^\d+$/,					conversion_function : function(row) {						var cell = $(row.row.getElementsByTagName('td')[this.sort_column])								.get('text');						var cellparts = cell.split('.');						var integer = cellparts[0];						var decimal = cellparts[1] ? "." + cellparts[1] : "";						return '00000000000000000000000000000000'.substr(0,								32 - integer.length).concat(integer)								.concat(decimal);					}				},				// KEP - Supports numbers like 3/2 - often used for bed/bath or full/half bath. (Application-specific)				// Bed/Bath				{					matcher : /^\d(\/\d)?$/,					conversion_function : function(row) {						var cell = $(row.row.getElementsByTagName('td')[this.sort_column])								.get('text');						var cellparts = cell.split('/');						var integer = cellparts[0];						var decimal = cellparts[1] ? "." + cellparts[1] : "";						return '00000000000000000000000000000000'.substr(0,								32 - integer.length).concat(integer)								.concat(decimal);					}				},				// 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');	});}
