// Stupid jQuery table plugin. //http://joequery.github.com/Stupid-Table-Plugin/ // Call on a table // sortFns: Sort functions for your datatypes. (function($){ $.fn.stupidtable = function(sortFns){ var table = this; sortFns = sortFns || {}; // ==================================================== // // Utility functions // // ==================================================== // // Merge sort functions with some default sort functions. sortFns = $.extend({}, { "int":function(a,b){ return parseInt(a, 10) - parseInt(b, 10); }, "float":function(a,b){ return parseFloat(a) - parseFloat(b); }, "string":function(a,b){ if (a<b) return -1; if (a>b) return +1; return 0;} }, sortFns); // Array comparison. See http://stackoverflow.com/a/8618383 var arrays_equal = function(a,b) { return !!a && !!b && !(a<b || b<a);} // Return the resulting indexes of a sort so we can apply // this result elsewhere. This returns an array of index numbers. // return[0] = x means "arr's 0th element is now at x" var sort_map = function(arr, sort_function){ var sorted = arr.slice(0).sort(sort_function); var map = []; var index = 0; for(var i=0; i<arr.length; i++){ index = $.inArray(arr[i], sorted); // If this index is already in the map, look for the next index. // This handles the case of duplicate entries. while($.inArray(index, map) != -1){ index++; } map.push(index); } return map; } // Apply a sort map to the array. var apply_sort_map = function(arr, map){ var clone = arr.slice(0); for(var i=0; i<map.length; i++){ newIndex = map[i]; clone[newIndex] = arr[i]; } return clone; } // Returns true if array is sorted, false otherwise. // Checks for both ascending and descending var is_sorted_array = function(arr, sort_function){ var clone = arr.slice(0); var reversed = arr.slice(0).reverse(); var sorted = arr.slice(0).sort(sort_function); // Check if the array is sorted in either direction. return arrays_equal(clone, sorted) || arrays_equal(reversed, sorted); } var what_order_sorted = function(data, sf, isa) { var tmp = [data[0], data[data.length - 1]]; tmp.sort(sf); if(data[0] == tmp[0] || !isa) { return 'desc'; }else{ return 'asc'; } } // ==================================================== // // Begin execution! // // ==================================================== // // Do sorting when THs are clicked table.delegate("th:not(.dontsort)", "click", function(){ if($(this).text().replace(/ /g, '') == '') { // empty header, don't allow sorting return; } var trs = table.find("tbody tr"); var i = $(this).index(); var classes = $(this).attr("class"); var type = null; if (classes){ classes = classes.split(/\s+/); for(var j=0; j<classes.length; j++){ if(classes[j].search("sort-type-") != -1){ type = classes[j].replace('sort-', ''); break; } } if(type){ type = type.split('-')[1]; } else{ type = "string"; } } // Don't attempt to sort if no data type //if(!type){return false;} var sortMethod = sortFns[type]; // Gather the elements for this column column = []; // Push either the value of the 'data-order-by' attribute if specified // or just the text() value in this column to column[] for comparison. trs.each(function(index,tr){ var e = $(tr).children().eq(i); var order_by = e.attr('data-order-by') || e.text(); column.push(order_by); }); // If the column is already sorted, just reverse the order. The sort // map is just reversing the indexes. if(is_sorted_array(column, sortMethod)){ column.reverse(); var theMap = []; for(var i=column.length-1; i>=0; i--){ theMap.push(i); } }else{ // Get a sort map and apply to all rows theMap = sort_map(column, sortMethod); } // remove old sort classes (on this and other columns) $(this).parent().find('th').each(function() { $(this).removeClass('sortasc sortdesc'); }); // what order are we sorting in? var whatorder = what_order_sorted(column, sortMethod, is_sorted_array(column, sortMethod)); // set new sort class $(this).addClass(whatorder == 'asc' ? 'sortasc' : 'sortdesc'); var sortedTRs = $(apply_sort_map(trs, theMap)); // Replace the content of tbody with the sortedTRs. Strangely (and // conveniently!) enough, .append accomplishes this for us. table.find("tbody").append(sortedTRs); }); // remove th icon if no header text $(this).find('th').each(function() { var hv = $(this).text().replace(/ /g, ''); if(hv == '') { $(this).css('background', 'transparent'); } }); } })(jQuery); $('table.sortable').each(function() { var rows = $(this).find('tbody tr').length; if(rows > 1) { $(this).stupidtable(); }else{ $(this).removeClass('sortable'); } });