sorter.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* eslint-disable */
  2. var addSorting = (function () {
  3. 'use strict';
  4. var cols,
  5. currentSort = {
  6. index: 0,
  7. desc: false,
  8. };
  9. // returns the summary table element
  10. function getTable() {
  11. return document.querySelector('.coverage-summary');
  12. }
  13. // returns the thead element of the summary table
  14. function getTableHeader() {
  15. return getTable().querySelector('thead tr');
  16. }
  17. // returns the tbody element of the summary table
  18. function getTableBody() {
  19. return getTable().querySelector('tbody');
  20. }
  21. // returns the th element for nth column
  22. function getNthColumn(n) {
  23. return getTableHeader().querySelectorAll('th')[n];
  24. }
  25. function onFilterInput() {
  26. const searchValue = document.getElementById('fileSearch').value;
  27. const rows = document.getElementsByTagName('tbody')[0].children;
  28. for (let i = 0; i < rows.length; i++) {
  29. const row = rows[i];
  30. if (row.textContent.toLowerCase().includes(searchValue.toLowerCase())) {
  31. row.style.display = '';
  32. } else {
  33. row.style.display = 'none';
  34. }
  35. }
  36. }
  37. // loads the search box
  38. function addSearchBox() {
  39. var template = document.getElementById('filterTemplate');
  40. var templateClone = template.content.cloneNode(true);
  41. templateClone.getElementById('fileSearch').oninput = onFilterInput;
  42. template.parentElement.appendChild(templateClone);
  43. }
  44. // loads all columns
  45. function loadColumns() {
  46. var colNodes = getTableHeader().querySelectorAll('th'),
  47. colNode,
  48. cols = [],
  49. col,
  50. i;
  51. for (i = 0; i < colNodes.length; i += 1) {
  52. colNode = colNodes[i];
  53. col = {
  54. key: colNode.getAttribute('data-col'),
  55. sortable: !colNode.getAttribute('data-nosort'),
  56. type: colNode.getAttribute('data-type') || 'string',
  57. };
  58. cols.push(col);
  59. if (col.sortable) {
  60. col.defaultDescSort = col.type === 'number';
  61. colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
  62. }
  63. }
  64. return cols;
  65. }
  66. // attaches a data attribute to every tr element with an object
  67. // of data values keyed by column name
  68. function loadRowData(tableRow) {
  69. var tableCols = tableRow.querySelectorAll('td'),
  70. colNode,
  71. col,
  72. data = {},
  73. i,
  74. val;
  75. for (i = 0; i < tableCols.length; i += 1) {
  76. colNode = tableCols[i];
  77. col = cols[i];
  78. val = colNode.getAttribute('data-value');
  79. if (col.type === 'number') {
  80. val = Number(val);
  81. }
  82. data[col.key] = val;
  83. }
  84. return data;
  85. }
  86. // loads all row data
  87. function loadData() {
  88. var rows = getTableBody().querySelectorAll('tr'),
  89. i;
  90. for (i = 0; i < rows.length; i += 1) {
  91. rows[i].data = loadRowData(rows[i]);
  92. }
  93. }
  94. // sorts the table using the data for the ith column
  95. function sortByIndex(index, desc) {
  96. var key = cols[index].key,
  97. sorter = function (a, b) {
  98. a = a.data[key];
  99. b = b.data[key];
  100. return a < b ? -1 : a > b ? 1 : 0;
  101. },
  102. finalSorter = sorter,
  103. tableBody = document.querySelector('.coverage-summary tbody'),
  104. rowNodes = tableBody.querySelectorAll('tr'),
  105. rows = [],
  106. i;
  107. if (desc) {
  108. finalSorter = function (a, b) {
  109. return -1 * sorter(a, b);
  110. };
  111. }
  112. for (i = 0; i < rowNodes.length; i += 1) {
  113. rows.push(rowNodes[i]);
  114. tableBody.removeChild(rowNodes[i]);
  115. }
  116. rows.sort(finalSorter);
  117. for (i = 0; i < rows.length; i += 1) {
  118. tableBody.appendChild(rows[i]);
  119. }
  120. }
  121. // removes sort indicators for current column being sorted
  122. function removeSortIndicators() {
  123. var col = getNthColumn(currentSort.index),
  124. cls = col.className;
  125. cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
  126. col.className = cls;
  127. }
  128. // adds sort indicators for current column being sorted
  129. function addSortIndicators() {
  130. getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
  131. }
  132. // adds event listeners for all sorter widgets
  133. function enableUI() {
  134. var i,
  135. el,
  136. ithSorter = function ithSorter(i) {
  137. var col = cols[i];
  138. return function () {
  139. var desc = col.defaultDescSort;
  140. if (currentSort.index === i) {
  141. desc = !currentSort.desc;
  142. }
  143. sortByIndex(i, desc);
  144. removeSortIndicators();
  145. currentSort.index = i;
  146. currentSort.desc = desc;
  147. addSortIndicators();
  148. };
  149. };
  150. for (i = 0; i < cols.length; i += 1) {
  151. if (cols[i].sortable) {
  152. // add the click event handler on the th so users
  153. // dont have to click on those tiny arrows
  154. el = getNthColumn(i).querySelector('.sorter').parentElement;
  155. if (el.addEventListener) {
  156. el.addEventListener('click', ithSorter(i));
  157. } else {
  158. el.attachEvent('onclick', ithSorter(i));
  159. }
  160. }
  161. }
  162. }
  163. // adds sorting functionality to the UI
  164. return function () {
  165. if (!getTable()) {
  166. return;
  167. }
  168. cols = loadColumns();
  169. loadData();
  170. addSearchBox();
  171. addSortIndicators();
  172. enableUI();
  173. };
  174. })();
  175. window.addEventListener('load', addSorting);