sorter.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. // Try to create a RegExp from the searchValue. If it fails (invalid regex),
  29. // it will be treated as a plain text search
  30. let searchRegex;
  31. try {
  32. searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive
  33. } catch (error) {
  34. searchRegex = null;
  35. }
  36. for (let i = 0; i < rows.length; i++) {
  37. const row = rows[i];
  38. let isMatch = false;
  39. if (searchRegex) {
  40. // If a valid regex was created, use it for matching
  41. isMatch = searchRegex.test(row.textContent);
  42. } else {
  43. // Otherwise, fall back to the original plain text search
  44. isMatch = row.textContent
  45. .toLowerCase()
  46. .includes(searchValue.toLowerCase());
  47. }
  48. row.style.display = isMatch ? '' : 'none';
  49. }
  50. }
  51. // loads the search box
  52. function addSearchBox() {
  53. var template = document.getElementById('filterTemplate');
  54. var templateClone = template.content.cloneNode(true);
  55. templateClone.getElementById('fileSearch').oninput = onFilterInput;
  56. template.parentElement.appendChild(templateClone);
  57. }
  58. // loads all columns
  59. function loadColumns() {
  60. var colNodes = getTableHeader().querySelectorAll('th'),
  61. colNode,
  62. cols = [],
  63. col,
  64. i;
  65. for (i = 0; i < colNodes.length; i += 1) {
  66. colNode = colNodes[i];
  67. col = {
  68. key: colNode.getAttribute('data-col'),
  69. sortable: !colNode.getAttribute('data-nosort'),
  70. type: colNode.getAttribute('data-type') || 'string'
  71. };
  72. cols.push(col);
  73. if (col.sortable) {
  74. col.defaultDescSort = col.type === 'number';
  75. colNode.innerHTML =
  76. colNode.innerHTML + '<span class="sorter"></span>';
  77. }
  78. }
  79. return cols;
  80. }
  81. // attaches a data attribute to every tr element with an object
  82. // of data values keyed by column name
  83. function loadRowData(tableRow) {
  84. var tableCols = tableRow.querySelectorAll('td'),
  85. colNode,
  86. col,
  87. data = {},
  88. i,
  89. val;
  90. for (i = 0; i < tableCols.length; i += 1) {
  91. colNode = tableCols[i];
  92. col = cols[i];
  93. val = colNode.getAttribute('data-value');
  94. if (col.type === 'number') {
  95. val = Number(val);
  96. }
  97. data[col.key] = val;
  98. }
  99. return data;
  100. }
  101. // loads all row data
  102. function loadData() {
  103. var rows = getTableBody().querySelectorAll('tr'),
  104. i;
  105. for (i = 0; i < rows.length; i += 1) {
  106. rows[i].data = loadRowData(rows[i]);
  107. }
  108. }
  109. // sorts the table using the data for the ith column
  110. function sortByIndex(index, desc) {
  111. var key = cols[index].key,
  112. sorter = function(a, b) {
  113. a = a.data[key];
  114. b = b.data[key];
  115. return a < b ? -1 : a > b ? 1 : 0;
  116. },
  117. finalSorter = sorter,
  118. tableBody = document.querySelector('.coverage-summary tbody'),
  119. rowNodes = tableBody.querySelectorAll('tr'),
  120. rows = [],
  121. i;
  122. if (desc) {
  123. finalSorter = function(a, b) {
  124. return -1 * sorter(a, b);
  125. };
  126. }
  127. for (i = 0; i < rowNodes.length; i += 1) {
  128. rows.push(rowNodes[i]);
  129. tableBody.removeChild(rowNodes[i]);
  130. }
  131. rows.sort(finalSorter);
  132. for (i = 0; i < rows.length; i += 1) {
  133. tableBody.appendChild(rows[i]);
  134. }
  135. }
  136. // removes sort indicators for current column being sorted
  137. function removeSortIndicators() {
  138. var col = getNthColumn(currentSort.index),
  139. cls = col.className;
  140. cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
  141. col.className = cls;
  142. }
  143. // adds sort indicators for current column being sorted
  144. function addSortIndicators() {
  145. getNthColumn(currentSort.index).className += currentSort.desc
  146. ? ' sorted-desc'
  147. : ' sorted';
  148. }
  149. // adds event listeners for all sorter widgets
  150. function enableUI() {
  151. var i,
  152. el,
  153. ithSorter = function ithSorter(i) {
  154. var col = cols[i];
  155. return function() {
  156. var desc = col.defaultDescSort;
  157. if (currentSort.index === i) {
  158. desc = !currentSort.desc;
  159. }
  160. sortByIndex(i, desc);
  161. removeSortIndicators();
  162. currentSort.index = i;
  163. currentSort.desc = desc;
  164. addSortIndicators();
  165. };
  166. };
  167. for (i = 0; i < cols.length; i += 1) {
  168. if (cols[i].sortable) {
  169. // add the click event handler on the th so users
  170. // dont have to click on those tiny arrows
  171. el = getNthColumn(i).querySelector('.sorter').parentElement;
  172. if (el.addEventListener) {
  173. el.addEventListener('click', ithSorter(i));
  174. } else {
  175. el.attachEvent('onclick', ithSorter(i));
  176. }
  177. }
  178. }
  179. }
  180. // adds sorting functionality to the UI
  181. return function() {
  182. if (!getTable()) {
  183. return;
  184. }
  185. cols = loadColumns();
  186. loadData();
  187. addSearchBox();
  188. addSortIndicators();
  189. enableUI();
  190. };
  191. })();
  192. window.addEventListener('load', addSorting);