| 8 | 1 // Stupid jQuery table plugin. | 
|  | 2 | 
|  | 3 // Call on a table | 
|  | 4 // sortFns: Sort functions for your datatypes. | 
|  | 5 (function($) { | 
|  | 6 | 
|  | 7   $.fn.stupidtable = function(sortFns) { | 
|  | 8     return this.each(function() { | 
|  | 9       var $table = $(this); | 
|  | 10       sortFns = sortFns || {}; | 
|  | 11 | 
|  | 12       // ==================================================== // | 
|  | 13       //                  Utility functions                   // | 
|  | 14       // ==================================================== // | 
|  | 15 | 
|  | 16       // Merge sort functions with some default sort functions. | 
|  | 17       sortFns = $.extend({}, $.fn.stupidtable.default_sort_fns, sortFns); | 
|  | 18 | 
|  | 19       // Return the resulting indexes of a sort so we can apply | 
|  | 20       // this result elsewhere. This returns an array of index numbers. | 
|  | 21       // return[0] = x means "arr's 0th element is now at x" | 
|  | 22       var sort_map = function(arr, sort_function) { | 
|  | 23         var map = []; | 
|  | 24         var index = 0; | 
|  | 25         var sorted = arr.slice(0).sort(sort_function); | 
|  | 26         for (var i=0; i<arr.length; i++) { | 
|  | 27             index = $.inArray(arr[i], sorted); | 
|  | 28 | 
|  | 29             // If this index is already in the map, look for the next index. | 
|  | 30             // This handles the case of duplicate entries. | 
|  | 31             while ($.inArray(index, map) != -1) { | 
|  | 32                 index++; | 
|  | 33             } | 
|  | 34             map.push(index); | 
|  | 35         } | 
|  | 36 | 
|  | 37         return map; | 
|  | 38       }; | 
|  | 39 | 
|  | 40       // Apply a sort map to the array. | 
|  | 41       var apply_sort_map = function(arr, map) { | 
|  | 42         var clone = arr.slice(0), | 
|  | 43             newIndex = 0; | 
|  | 44         for (var i=0; i<map.length; i++) { | 
|  | 45           newIndex = map[i]; | 
|  | 46           clone[newIndex] = arr[i]; | 
|  | 47         } | 
|  | 48         return clone; | 
|  | 49       }; | 
|  | 50 | 
|  | 51       // ==================================================== // | 
|  | 52       //                  Begin execution!                    // | 
|  | 53       // ==================================================== // | 
|  | 54 | 
|  | 55       // Do sorting when THs are clicked | 
|  | 56       $table.on("click", "th", function() { | 
|  | 57         var trs = $table.children("tbody").children("tr"); | 
|  | 58         var $this = $(this); | 
|  | 59         var th_index = 0; | 
|  | 60         var dir = $.fn.stupidtable.dir; | 
|  | 61 | 
|  | 62         $table.find("th").slice(0, $this.index()).each(function() { | 
|  | 63           var cols = $(this).attr("colspan") || 1; | 
|  | 64           th_index += parseInt(cols,10); | 
|  | 65         }); | 
|  | 66 | 
|  | 67         // Determine (and/or reverse) sorting direction, default `asc` | 
|  | 68         var sort_dir = $this.data("sort-default") || dir.ASC; | 
|  | 69         if ($this.data("sort-dir")) | 
|  | 70            sort_dir = $this.data("sort-dir") === dir.ASC ? dir.DESC : dir.ASC; | 
|  | 71 | 
|  | 72         // Choose appropriate sorting function. | 
|  | 73         var type = $this.data("sort") || null; | 
|  | 74 | 
|  | 75         // Prevent sorting if no type defined | 
|  | 76         if (type === null) { | 
|  | 77           return; | 
|  | 78         } | 
|  | 79 | 
|  | 80         // Trigger `beforetablesort` event that calling scripts can hook into; | 
|  | 81         // pass parameters for sorted column index and sorting direction | 
|  | 82         $table.trigger("beforetablesort", {column: th_index, direction: sort_dir}); | 
|  | 83         // More reliable method of forcing a redraw | 
|  | 84         $table.css("display"); | 
|  | 85 | 
|  | 86         // Run sorting asynchronously on a timout to force browser redraw after | 
|  | 87         // `beforetablesort` callback. Also avoids locking up the browser too much. | 
|  | 88         setTimeout(function() { | 
|  | 89           // Gather the elements for this column | 
|  | 90           var column = []; | 
|  | 91           var sortMethod = sortFns[type]; | 
|  | 92 | 
|  | 93           // Push either the value of the `data-order-by` attribute if specified | 
|  | 94           // or just the text() value in this column to column[] for comparison. | 
|  | 95           trs.each(function(index,tr) { | 
|  | 96             var $e = $(tr).children().eq(th_index); | 
|  | 97             var sort_val = $e.data("sort-value"); | 
|  | 98             var order_by = typeof(sort_val) !== "undefined" ? sort_val : $e.text(); | 
|  | 99             column.push(order_by); | 
|  | 100           }); | 
|  | 101 | 
|  | 102           // Create the sort map. This column having a sort-dir implies it was | 
|  | 103           // the last column sorted. As long as no data-sort-desc is specified, | 
|  | 104           // we're free to just reverse the column. | 
|  | 105           var theMap; | 
|  | 106           if (sort_dir == dir.ASC) | 
|  | 107             theMap = sort_map(column, sortMethod); | 
|  | 108           else | 
|  | 109             theMap = sort_map(column, function(a, b) { return -sortMethod(a, b); }); | 
|  | 110 | 
|  | 111           // Reset siblings | 
|  | 112           $table.find("th").data("sort-dir", null).removeClass("sorting-desc sorting-asc"); | 
|  | 113           $this.data("sort-dir", sort_dir).addClass("sorting-"+sort_dir); | 
|  | 114 | 
|  | 115           var sortedTRs = $(apply_sort_map(trs, theMap)); | 
|  | 116           $table.children("tbody").remove(); | 
|  | 117           $table.append("<tbody />").append(sortedTRs); | 
|  | 118 | 
|  | 119           // Trigger `aftertablesort` event. Similar to `beforetablesort` | 
|  | 120           $table.trigger("aftertablesort", {column: th_index, direction: sort_dir}); | 
|  | 121           // More reliable method of forcing a redraw | 
|  | 122           $table.css("display"); | 
|  | 123         }, 10); | 
|  | 124       }); | 
|  | 125     }); | 
|  | 126   }; | 
|  | 127 | 
|  | 128   // Enum containing sorting directions | 
|  | 129   $.fn.stupidtable.dir = {ASC: "asc", DESC: "desc"}; | 
|  | 130 | 
|  | 131   $.fn.stupidtable.default_sort_fns = { | 
|  | 132     "int": function(a, b) { | 
|  | 133       return parseInt(a, 10) - parseInt(b, 10); | 
|  | 134     }, | 
|  | 135     "float": function(a, b) { | 
|  | 136       return parseFloat(a) - parseFloat(b); | 
|  | 137     }, | 
|  | 138     "string": function(a, b) { | 
|  | 139       if (a < b) return -1; | 
|  | 140       if (a > b) return +1; | 
|  | 141       return 0; | 
|  | 142     }, | 
|  | 143     "string-ins": function(a, b) { | 
|  | 144       a = a.toLowerCase(); | 
|  | 145       b = b.toLowerCase(); | 
|  | 146       if (a < b) return -1; | 
|  | 147       if (a > b) return +1; | 
|  | 148       return 0; | 
|  | 149     } | 
|  | 150   }; | 
|  | 151 | 
|  | 152 })(jQuery); |