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