sorter.js 6.0 KB

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