jquery.tableSort.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* ===============================
  2. | TABLESORT.JS
  3. | Copyright, Andy Croxall (mitya@mitya.co.uk)
  4. | For documentation and demo see http://mitya.co.uk/scripts/Animated-table-sort-REGEXP-friendly-111
  5. |
  6. | USAGE
  7. | This script may be used, distributed and modified freely but this header must remain in tact.
  8. | For usage info and demo, including info on args and params, see www.mitya.co.uk/scripts
  9. =============================== */
  10. jQuery.fn.sortTable = function(params) {
  11. /*-----------
  12. | STOP right now if anim already in progress
  13. -----------*/
  14. if ($(this).find(':animated').length > 0) return;
  15. /*-----------
  16. | VALIDATE TABLE & PARAMS
  17. | - if no col to sort on passed, complain and return
  18. | - if table doesn't contain requested col, complain and return
  19. | If !sortType or invalid sortType, assume ascii sort
  20. -----------*/
  21. var error = null;
  22. var complain = null;
  23. if (!params.onCol) { error = "No column specified to search on"; complain = true; }
  24. else if ($(this).find('td:nth-child('+params.onCol+')').length == 0) { error = "The requested column wasn't found in the table"; complain = true; }
  25. if (error) { if (complain) alert(error); return; }
  26. if (!params.sortType || params.sortType != 'numeric') params.sortType = 'ascii';
  27. /*-----------
  28. | PREP
  29. | - declare array to store the contents of each <td>, or, if sorting on regexp, the pattern match of the regexp in each <td>
  30. | - Give the <table> position: relative to aid animation
  31. | - Mark the col we're sorting on with an identifier class
  32. -----------*/
  33. var valuesToSort = [];
  34. $(this).css('position', 'relative');
  35. var doneAnimating = 0;
  36. var tdSelectorText = 'td'+(!params.onCol ? '' : ':nth-child('+params.onCol+')');
  37. $(this).find('td:nth-child('+params.onCol+')').addClass('sortOnThisCol');
  38. var thiss = this;
  39. /*-----------
  40. | Iterate over table and. For each:
  41. | - append its content / regexp match (see above) to valuesToSort[]
  42. | - create a new <div>, give it position: absolute and copy over the <td>'s content into it
  43. | - fix the <td>'s width/height to its offset width/height so that, when we remove its html, it won't change shape
  44. | - clear the <td>'s content
  45. | - clear the <td>'s content
  46. | There is no visual effect in this. But it means each <td>'s content is now 'animatable', since it's position: absolute.
  47. -----------*/
  48. var counter = 0;
  49. $(this).find('td').each(function() {
  50. if ($(this).is('.sortOnThisCol') || (!params.onCol && !params.keepRelationships)) {
  51. var valForSort = !params.child ? $(this).text() : (params.child != 'input' ? $(this).find(params.child).text() : $(this).find(params.child).val());
  52. if (params.regexp) {
  53. valForSort = valForSort.match(new RegExp(params.regexp))[!params.regexpIndex ? 0 : params.regexpIndex];
  54. }
  55. valuesToSort.push(valForSort);
  56. }
  57. var thisTDHTMLHolder = document.createElement('div');
  58. with($(thisTDHTMLHolder)) {
  59. html($(this).html());
  60. if (params.child && params.child == 'input') html(html().replace(/<input /, "<input value='"+$(this).find(params.child).val()+"'", html()));
  61. css({position: 'relative', left: 0, top: 0});
  62. }
  63. $(this).html('');
  64. $(this).append(thisTDHTMLHolder);
  65. counter++;
  66. });
  67. /*-----------
  68. | Sort values array.
  69. | - Sort (either simply, on ascii, or numeric if sortNumeric == true)
  70. | - If descending == true, reverse after sort
  71. -----------*/
  72. params.sortType == 'numeric' ? valuesToSort.sort(function(a, b) { return (a.replace(/[^\d\.]/g, '', a)-b.replace(/[^\d\.]/g, '', b)); }) : valuesToSort.sort();
  73. if (params.sortDesc) {
  74. valuesToSort_tempCopy = [];
  75. for(var u=valuesToSort.length; u--; u>=0) valuesToSort_tempCopy.push(valuesToSort[u]);
  76. valuesToSort = valuesToSort_tempCopy;
  77. delete(valuesToSort_tempCopy)
  78. }
  79. /*-----------
  80. | Now, for each:
  81. -----------*/
  82. for(var k in valuesToSort) {
  83. //establish current <td> relating to this value of the array
  84. var currTD = $($(this).find(tdSelectorText).filter(function() {
  85. return (
  86. (
  87. !params.regexp
  88. &&
  89. (
  90. (
  91. params.child
  92. &&
  93. (
  94. (
  95. params.child != 'input'
  96. &&
  97. valuesToSort[k] == $(this).find(params.child).text()
  98. )
  99. ||
  100. params.child == 'input'
  101. &&
  102. valuesToSort[k] == $(this).find(params.child).val()
  103. )
  104. )
  105. ||
  106. (
  107. !params.child
  108. &&
  109. valuesToSort[k] == $(this).children('div').html()
  110. )
  111. )
  112. )
  113. ||
  114. (
  115. params.regexp
  116. &&
  117. $(this).children('div').html().match(new RegExp(params.regexp))[!params.regexpIndex ? 0 : params.regexpIndex] == valuesToSort[k]
  118. )
  119. )
  120. &&
  121. !$(this).hasClass('tableSort_TDRepopulated');
  122. }).get(0));
  123. //give current <td> a class to mark it as having been used, so we don't get confused with duplicate values
  124. currTD.addClass('tableSort_TDRepopulated');
  125. //establish target <td> for this value and store as a node reference on this <td>
  126. var targetTD = $($(this).find(tdSelectorText).get(k));
  127. currTD.get(0).toTD = targetTD;
  128. //if we're sorting on a particular column and maintaining relationships, also give the other <td>s in rows a node reference
  129. //denoting ITS target, so they move with their lead siibling
  130. if (params.keepRelationships) {
  131. var counter = 0;
  132. $(currTD).parent().children('td').each(function() {
  133. $(this).get(0).toTD = $(targetTD.parent().children().get(counter));
  134. counter++;
  135. });
  136. }
  137. //establish current relative positions for the current and target <td>s and use this to calculate how far each <div> needs to move
  138. var currPos = currTD.position();
  139. var targetPos = targetTD.position();
  140. var moveBy_top = targetPos.top - currPos.top;
  141. //invert values if going backwards/upwards
  142. if (targetPos.top > currPos.top) moveBy_top = Math.abs(moveBy_top);
  143. /*-----------
  144. | ANIMATE
  145. | - work out what to animate on.
  146. | - if !keepRelationships, animate only <td>s in the col we're sorting on (identified by .sortOnThisCol)
  147. | - if keepRelationships, animate all cols but <td>s that aren't .sortOnThisCol follow lead sibiling with .sortOnThisCol
  148. | - run animation. On callback, update each <td> with content of <div> that just moved into it and remove <div>s
  149. | - If noAnim, we'll still run aniamte() but give it a low duration so it appears instant
  150. -----------*/
  151. var animateOn = params.keepRelationships ? currTD.add(currTD.siblings()) : currTD;
  152. var done = 0;
  153. animateOn.children('div').animate({top: moveBy_top}, !params.noAnim ? 500 : 0, null, function() {
  154. if ($(this).parent().is('.sortOnThisCol') || !params.keepRelationships) {
  155. done++;
  156. if (done == valuesToSort.length-1) thiss.tableSort_cleanUp();
  157. }
  158. });
  159. }
  160. };
  161. jQuery.fn.tableSort_cleanUp = function() {
  162. /*-----------
  163. | AFTER ANIM
  164. | - assign each <td> its new content as property of it (DON'T populate it yet - this <td> may still need to be read by
  165. | other <td>s' toTD node references
  166. | - once new contents for each <td> gathered, populate
  167. | - remove some identifier classes and properties
  168. -----------*/
  169. $(this).find('td').each(function() {
  170. if($(this).get(0).toTD) $($(this).get(0).toTD).get(0).newHTML = $(this).children('div').html();
  171. });
  172. $(this).find('td').each(function() { $(this).html($(this).get(0).newHTML); });
  173. $('td.tableSort_TDRepopulated').removeClass('tableSort_TDRepopulated');
  174. $(this).find('.sortOnThisCol').removeClass('sortOnThisCol');
  175. $(this).find('td[newHTML]').attr('newHTML', '');
  176. $(this).find('td[toTD]').attr('toTD', '');
  177. };