logo

blog

My website can't be that messy, right? git clone https://hacktivis.me/git/blog.git

sorttable.js (4256B)


  1. /*
  2. * Copyright 2007 Stuart Langridge http://www.kryogenix.org/code/browser/sorttable/
  3. * Copyright 2018, 2023 Haelwenn (lanodan) Monnier <contact@hacktivis.me>
  4. * SPDX-License-Identifier: X11
  5. */
  6. /* Usage:
  7. * Add <script src="sorttable.js"></script> to your (x)HTML pages
  8. * Add class="sortable" to any table you'd like to make sortable
  9. * See sorttable.css for an example of styling
  10. */
  11. sorttable = {
  12. done : false
  13. };
  14. sorttable.init = function() {
  15. // quit if this function has already been called
  16. if(sorttable.done) return;
  17. // flag this function so we don't do the same thing twice
  18. sorttable.done = true;
  19. var sortableElements = document.getElementsByClassName("sortable");
  20. Array.prototype.filter.call(sortableElements, function(sortableElement) {
  21. if(sortableElement.nodeName == "TABLE" || sortableElement.nodeName == "table")
  22. {
  23. sorttable.makeSortable(sortableElement);
  24. }
  25. });
  26. };
  27. sorttable.makeSortable = function(table) {
  28. // Only one thead row is supported
  29. if(table.tHead.rows.length != 1) return;
  30. // work through each column and calculate its type
  31. headrow = table.tHead.rows[0].cells;
  32. for(var i = 0; i < headrow.length; i++)
  33. {
  34. // skip this col
  35. if(!headrow[i].classList.contains("sorttable_nosort"))
  36. {
  37. // make it clickable to sort
  38. headrow[i].sorttable_columnindex = i;
  39. headrow[i].sorttable_tbody = table.tBodies[0];
  40. headrow[i].addEventListener("click", event => {
  41. if(event.target)
  42. {
  43. sorttable.innerSortFunction(event.target)
  44. }
  45. });
  46. headrow[i].addEventListener("keydown", event => {
  47. if(event.target && (event.key && event.key == "Enter"))
  48. {
  49. sorttable.innerSortFunction(event.target);
  50. }
  51. });
  52. headrow[i].setAttribute("tabindex", "0");
  53. headrow[i].classList.add('made_sortable');
  54. }
  55. }
  56. };
  57. sorttable.compareFn = function(a, b) {
  58. // Note: Returns are reversed
  59. if(a[0]<b[0]) {return 1};
  60. if(a[0]>b[0]) {return -1};
  61. return 0;
  62. };
  63. sorttable.innerSortFunction = function(tr) {
  64. if(tr.classList.contains("sorttable_sorted"))
  65. {
  66. sorttable.reverse(tr.sorttable_tbody);
  67. tr.classList.replace('sorttable_sorted', 'sorttable_sorted_reverse');
  68. }
  69. else if(tr.classList.contains("sorttable_sorted_reverse"))
  70. {
  71. sorttable.reverse(tr.sorttable_tbody);
  72. tr.classList.replace('sorttable_sorted_reverse', 'sorttable_sorted');
  73. }
  74. else
  75. {
  76. // remove sorttable_sorted classes
  77. theadRow = tr.parentNode;
  78. theadRow.childNodes.forEach(function(
  79. cell) { cell.classList.remove('sorttable_sorted_reverse', 'sorttable_sorted'); });
  80. // build an array to sort. This is a Schwartzian transform thing,
  81. // i.e., we "decorate" each row with the actual sort key,
  82. // sort based on the sort keys, and then put the rows back in order
  83. // which is a lot faster because you only do getInnerText once per row
  84. row_array = [];
  85. col = tr.sorttable_columnindex;
  86. rows = tr.sorttable_tbody.rows;
  87. for(var j = 0; j < rows.length; j++)
  88. {
  89. row_array[row_array.length] =
  90. [ sorttable.getElementValue(rows[j].cells[col]), rows[j] ];
  91. }
  92. row_array.sort(sorttable.compareFn);
  93. tb = tr.sorttable_tbody;
  94. row_array.forEach(function(row) { tb.appendChild(row[1]); });
  95. tr.classList.add('sorttable_sorted');
  96. }
  97. };
  98. // - Use data-value="" attribute if you want to override innerHTML
  99. // - Use data-type="" attribute if you want to use non-lexical sorting
  100. // Example: <td data-value="1337" data-type="int">Leet</td>
  101. sorttable.getElementValue = function(element) {
  102. if(element === undefined)
  103. {
  104. return "\u0000"; // null
  105. console.log("Warning: Empty cells found");
  106. };
  107. let value = element.dataset.value ? element.dataset.value : element.innerText;
  108. switch(element.dataset.type)
  109. {
  110. case undefined:
  111. return value;
  112. case "int":
  113. var v = parseInt(value);
  114. return v != NaN ? v : value;
  115. case "float":
  116. var v = parseFloat(value);
  117. return v != NaN ? v : value;
  118. default:
  119. console.log(`Warning: Unhandled type ${element.dataset.type}`);
  120. return value;
  121. };
  122. };
  123. sorttable.reverse = function(tbody) {
  124. // reverse the rows in a tbody
  125. newrows = [];
  126. for(var i = 0; i < tbody.rows.length; i++)
  127. {
  128. newrows[newrows.length] = tbody.rows[i];
  129. }
  130. for(var i = newrows.length - 1; i >= 0; i--)
  131. {
  132. tbody.appendChild(newrows[i]);
  133. }
  134. delete newrows;
  135. };
  136. sorttable.init()