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);
|