Posted By

ginoplusio on 11/17/08


Tagged

javascript js table sort order


Versions (?)

Who likes this?

3 people have marked this snippet as a favorite

jamesming
wizard04
dvdrtrgn


Javascript sort table


 / Published in: JavaScript
 

URL: http://www.barattalo.it/

sorting a table through javascript

  1. /*
  2.   SortTable
  3.   version 2
  4.   7th April 2007
  5.   Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
  6.  
  7.   Instructions:
  8.   Download this file
  9.   Add <script src="sorttable.js"></script> to your HTML
  10.   Add class="sortable" to any table you'd like to make sortable
  11.   Click on the headers to sort
  12.  
  13.   Thanks to many, many people for contributions and suggestions.
  14.   Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
  15.   This basically means: do what you want with it.
  16. */
  17.  
  18.  
  19. var stIsIE = /*@cc_on!@*/false;
  20.  
  21. sorttable = {
  22. init: function() {
  23. // quit if this function has already been called
  24. if (arguments.callee.done) return;
  25. // flag this function so we don't do the same thing twice
  26. arguments.callee.done = true;
  27. // kill the timer
  28. if (_timer) clearInterval(_timer);
  29.  
  30. if (!document.createElement || !document.getElementsByTagName) return;
  31.  
  32. sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
  33.  
  34. forEach(document.getElementsByTagName('table'), function(table) {
  35. if (table.className.search(/\bsortable\b/) != -1) {
  36. sorttable.makeSortable(table);
  37. }
  38. });
  39.  
  40. },
  41.  
  42. makeSortable: function(table) {
  43. if (table.getElementsByTagName('thead').length == 0) {
  44. // table doesn't have a tHead. Since it should have, create one and
  45. // put the first table row in it.
  46. the = document.createElement('thead');
  47. the.appendChild(table.rows[0]);
  48. table.insertBefore(the,table.firstChild);
  49. }
  50. // Safari doesn't support table.tHead, sigh
  51. if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
  52.  
  53. if (table.tHead.rows.length != 1) return; // can't cope with two header rows
  54.  
  55. // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
  56. // "total" rows, for example). This is B&R, since what you're supposed
  57. // to do is put them in a tfoot. So, if there are sortbottom rows,
  58. // for backwards compatibility, move them to tfoot (creating it if needed).
  59. sortbottomrows = [];
  60. for (var i=0; i<table.rows.length; i++) {
  61. if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
  62. sortbottomrows[sortbottomrows.length] = table.rows[i];
  63. }
  64. }
  65. if (sortbottomrows) {
  66. if (table.tFoot == null) {
  67. // table doesn't have a tfoot. Create one.
  68. tfo = document.createElement('tfoot');
  69. table.appendChild(tfo);
  70. }
  71. for (var i=0; i<sortbottomrows.length; i++) {
  72. tfo.appendChild(sortbottomrows[i]);
  73. }
  74. delete sortbottomrows;
  75. }
  76.  
  77. // work through each column and calculate its type
  78. headrow = table.tHead.rows[0].cells;
  79. for (var i=0; i<headrow.length; i++) {
  80. // manually override the type with a sorttable_type attribute
  81. if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
  82. mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
  83. if (mtch) { override = mtch[1]; }
  84. if (mtch && typeof sorttable["sort_"+override] == 'function') {
  85. headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
  86. } else {
  87. headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
  88. }
  89. // make it clickable to sort
  90. headrow[i].sorttable_columnindex = i;
  91. headrow[i].sorttable_tbody = table.tBodies[0];
  92. dean_addEvent(headrow[i],"click", function(e) {
  93.  
  94. if (this.className.search(/\bsorttable_sorted\b/) != -1) {
  95. // if we're already sorted by this column, just
  96. // reverse the table, which is quicker
  97. sorttable.reverse(this.sorttable_tbody);
  98. this.className = this.className.replace('sorttable_sorted',
  99. 'sorttable_sorted_reverse');
  100. this.removeChild(document.getElementById('sorttable_sortfwdind'));
  101. sortrevind = document.createElement('span');
  102. sortrevind.id = "sorttable_sortrevind";
  103. sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
  104. this.appendChild(sortrevind);
  105. return;
  106. }
  107. if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
  108. // if we're already sorted by this column in reverse, just
  109. // re-reverse the table, which is quicker
  110. sorttable.reverse(this.sorttable_tbody);
  111. this.className = this.className.replace('sorttable_sorted_reverse',
  112. 'sorttable_sorted');
  113. this.removeChild(document.getElementById('sorttable_sortrevind'));
  114. sortfwdind = document.createElement('span');
  115. sortfwdind.id = "sorttable_sortfwdind";
  116. sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
  117. this.appendChild(sortfwdind);
  118. return;
  119. }
  120.  
  121. // remove sorttable_sorted classes
  122. theadrow = this.parentNode;
  123. forEach(theadrow.childNodes, function(cell) {
  124. if (cell.nodeType == 1) { // an element
  125. cell.className = cell.className.replace('sorttable_sorted_reverse','');
  126. cell.className = cell.className.replace('sorttable_sorted','');
  127. }
  128. });
  129. sortfwdind = document.getElementById('sorttable_sortfwdind');
  130. if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
  131. sortrevind = document.getElementById('sorttable_sortrevind');
  132. if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
  133.  
  134. this.className += ' sorttable_sorted';
  135. sortfwdind = document.createElement('span');
  136. sortfwdind.id = "sorttable_sortfwdind";
  137. sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
  138. this.appendChild(sortfwdind);
  139.  
  140. // build an array to sort. This is a Schwartzian transform thing,
  141. // i.e., we "decorate" each row with the actual sort key,
  142. // sort based on the sort keys, and then put the rows back in order
  143. // which is a lot faster because you only do getInnerText once per row
  144. row_array = [];
  145. col = this.sorttable_columnindex;
  146. rows = this.sorttable_tbody.rows;
  147. for (var j=0; j<rows.length; j++) {
  148. row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
  149. }
  150. /* If you want a stable sort, uncomment the following line */
  151. //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
  152. /* and comment out this one */
  153. row_array.sort(this.sorttable_sortfunction);
  154.  
  155. tb = this.sorttable_tbody;
  156. for (var j=0; j<row_array.length; j++) {
  157. tb.appendChild(row_array[j][1]);
  158. }
  159.  
  160. delete row_array;
  161. });
  162. }
  163. }
  164. },
  165.  
  166. guessType: function(table, column) {
  167. // guess the type of a column based on its first non-blank row
  168. sortfn = sorttable.sort_alpha;
  169. for (var i=0; i<table.tBodies[0].rows.length; i++) {
  170. text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
  171. if (text != '') {
  172. if (text.match(/^-?[�£$�¤]?[\d,.]+%?$/)) {
  173. return sorttable.sort_numeric;
  174. }
  175. // check for a date: dd/mm/yyyy or dd/mm/yy
  176. // can have / or . or - as separator
  177. // can be mm/dd as well
  178. possdate = text.match(sorttable.DATE_RE)
  179. if (possdate) {
  180. // looks like a date
  181. first = parseInt(possdate[1]);
  182. second = parseInt(possdate[2]);
  183. if (first > 12) {
  184. // definitely dd/mm
  185. return sorttable.sort_ddmm;
  186. } else if (second > 12) {
  187. return sorttable.sort_mmdd;
  188. } else {
  189. // looks like a date, but we can't tell which, so assume
  190. // that it's dd/mm (English imperialism!) and keep looking
  191. sortfn = sorttable.sort_ddmm;
  192. }
  193. }
  194. }
  195. }
  196. return sortfn;
  197. },
  198.  
  199. getInnerText: function(node) {
  200. // gets the text we want to use for sorting for a cell.
  201. // strips leading and trailing whitespace.
  202. // this is *not* a generic getInnerText function; it's special to sorttable.
  203. // for example, you can override the cell text with a customkey attribute.
  204. // it also gets .value for <input> fields.
  205.  
  206. hasInputs = (typeof node.getElementsByTagName == 'function') &&
  207. node.getElementsByTagName('input').length;
  208.  
  209. if (node.getAttribute("sorttable_customkey") != null) {
  210. return node.getAttribute("sorttable_customkey");
  211. }
  212. else if (typeof node.textContent != 'undefined' && !hasInputs) {
  213. return node.textContent.replace(/^\s+|\s+$/g, '');
  214. }
  215. else if (typeof node.innerText != 'undefined' && !hasInputs) {
  216. return node.innerText.replace(/^\s+|\s+$/g, '');
  217. }
  218. else if (typeof node.text != 'undefined' && !hasInputs) {
  219. return node.text.replace(/^\s+|\s+$/g, '');
  220. }
  221. else {
  222. switch (node.nodeType) {
  223. case 3:
  224. if (node.nodeName.toLowerCase() == 'input') {
  225. return node.value.replace(/^\s+|\s+$/g, '');
  226. }
  227. case 4:
  228. return node.nodeValue.replace(/^\s+|\s+$/g, '');
  229. break;
  230. case 1:
  231. case 11:
  232. var innerText = '';
  233. for (var i = 0; i < node.childNodes.length; i++) {
  234. innerText += sorttable.getInnerText(node.