Skip to content

Commit 10e9b8e

Browse files
NPM release 1.12.0; automatically infer sort classes (file-size-sort and runtime)
1 parent 4c2ed4e commit 10e9b8e

File tree

7 files changed

+190
-34
lines changed

7 files changed

+190
-34
lines changed

README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ Refer to the documenation for examples on how to use table-sort-js with [HTML](h
4141

4242
#### Classes:
4343

44-
| <table> classes | Description |
45-
| --------------------- | --------------------------------------------------------------------------------------------|
46-
| "table-sort" | Make the table sortable! (Words, numbers)... |
47-
| "table-arrows" | Display ascending or descending triangles. |
48-
| "no-class-infer" | Turns off inference for adding sort classes automatically (file-size-sort and runtime-sort).|
49-
| "remember-sort" | If clicking on different columns remembers sort of the original column. |
44+
| <table> classes | Description |
45+
| --------------------- | -------------------------------------------------------------------------------------------- |
46+
| "table-sort" | Make the table sortable! (Words, numbers)... |
47+
| "table-arrows" | Display ascending or descending triangles. |
48+
| "no-class-infer" | Turns off inference for adding sort classes automatically (file-size-sort and runtime-sort). |
49+
| "remember-sort" | If clicking on different columns remembers sort of the original column. |
5050

5151
| <th> classes | Description |
5252
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |

browser-extension/table-sort.js

+112-13
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,88 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
3535
}
3636
}
3737

38-
function makeTableSortable(sortableTable) {
38+
function createMissingTableHead(sortableTable) {
3939
let createTableHead;
40-
let tableBody;
40+
if (testingTableSortJS === true) {
41+
createTableHead = domDocumentWindow.createElement("thead");
42+
} else {
43+
createTableHead = document.createElement("thead");
44+
}
45+
createTableHead.appendChild(sortableTable.rows[0]);
46+
sortableTable.insertBefore(createTableHead, sortableTable.firstChild);
47+
}
48+
49+
function getTableBody(sortableTable) {
4150
if (sortableTable.getElementsByTagName("thead").length === 0) {
42-
if (testingTableSortJS === true) {
43-
createTableHead = domDocumentWindow.createElement("thead");
44-
} else {
45-
createTableHead = document.createElement("thead");
46-
}
47-
createTableHead.appendChild(sortableTable.rows[0]);
48-
sortableTable.insertBefore(createTableHead, sortableTable.firstChild);
51+
createMissingTableHead(sortableTable);
4952
if (sortableTable.querySelectorAll("tbody").length > 1) {
50-
tableBody = sortableTable.querySelectorAll("tbody")[1];
53+
return sortableTable.querySelectorAll("tbody")[1];
5154
} else {
52-
tableBody = sortableTable.querySelector("tbody");
55+
return sortableTable.querySelector("tbody");
5356
}
5457
} else {
55-
tableBody = sortableTable.querySelector("tbody");
58+
return sortableTable.querySelector("tbody");
59+
}
60+
}
61+
62+
function addInferredClass(th, columnLength, currentCount, classToAdd) {
63+
const threshold = columnLength / 2;
64+
if (currentCount >= threshold) {
65+
th.classList.add(classToAdd);
66+
}
67+
}
68+
69+
function inferSortClasses(tableRows, tableHeadHeaders) {
70+
for (let [columnIndex, th] of tableHeadHeaders.entries()) {
71+
const regexMinutesAndSeconds = /^(\d+h)?\s?(\d+m)?\s?(\d+s)?$/i;
72+
const regexFileSizeSort = /^([.0-9]+)\s?(B|KB|KiB|MB|MiB|GB|GiB|TB|TiB)/i;
73+
let runtimeSortCounter = 0,
74+
fileSizeSortCounter = 0;
75+
76+
let tableColumnLength = th.parentElement.childElementCount;
77+
for (let tr of tableRows) {
78+
let runtimeSortMatch, fileSizeSortMatch;
79+
const tableColumn = tr.querySelectorAll("td").item(columnIndex);
80+
if (tableColumn.innerText) {
81+
runtimeSortMatch = tableColumn.innerText.match(
82+
regexMinutesAndSeconds
83+
);
84+
fileSizeSortMatch = tableColumn.innerText.match(regexFileSizeSort);
85+
}
86+
if (runtimeSortMatch) {
87+
runtimeSortCounter++;
88+
}
89+
if (fileSizeSortMatch) {
90+
fileSizeSortCounter++;
91+
}
92+
}
93+
// TODO: refactor this into one function called addInferredClasses that loops over sort classes and counters
94+
addInferredClass(
95+
th,
96+
tableColumnLength,
97+
runtimeSortCounter,
98+
"runtime-sort"
99+
);
100+
addInferredClass(
101+
th,
102+
tableColumnLength,
103+
fileSizeSortCounter,
104+
"file-size-sort"
105+
);
56106
}
107+
}
57108

109+
function makeTableSortable(sortableTable) {
110+
const tableBody = getTableBody(sortableTable);
58111
const tableHead = sortableTable.querySelector("thead");
59112
const tableHeadHeaders = tableHead.querySelectorAll("th");
113+
const tableRows = tableBody.querySelectorAll("tr");
114+
115+
const isNoSortClassInference =
116+
sortableTable.classList.contains("no-class-infer");
117+
if (!isNoSortClassInference) {
118+
inferSortClasses(tableRows, tableHeadHeaders);
119+
}
60120

61121
for (let [columnIndex, th] of tableHeadHeaders.entries()) {
62122
if (!th.classList.contains("disable-sort")) {
@@ -116,6 +176,34 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
116176
}
117177
}
118178

179+
function sortByRuntime(tableRows, columnData) {
180+
for (let [i, tr] of tableRows.entries()) {
181+
const regexMinutesAndSeconds = /^(\d+h)?\s?(\d+m)?\s?(\d+s)?$/i;
182+
let columnOfTd = tr
183+
.querySelectorAll("td")
184+
.item(columnIndex).textContent;
185+
let match = columnOfTd.match(regexMinutesAndSeconds);
186+
let [minutesInSeconds, hours, seconds, timeinSeconds] = [0, 0, 0, 0];
187+
if (match) {
188+
const regexHours = match[1];
189+
if (regexHours) {
190+
hours = Number(regexHours.replace("h", "")) * 60 * 60;
191+
}
192+
const regexMinutes = match[2];
193+
if (regexMinutes) {
194+
minutesInSeconds = Number(regexMinutes.replace("m", "")) * 60;
195+
}
196+
const regexSeconds = match[3];
197+
if (regexSeconds) {
198+
seconds = Number(regexSeconds.replace("s", ""));
199+
}
200+
timeinSeconds = hours + minutesInSeconds + seconds;
201+
}
202+
columnData.push(`${timeinSeconds}#${i}`);
203+
columnIndexAndTableRow[columnData[i]] = tr.innerHTML;
204+
}
205+
}
206+
119207
let [timesClickedColumn, columnIndexesClicked] = [0, []];
120208

121209
function rememberSort(timesClickedColumn, columnIndexesClicked) {
@@ -146,6 +234,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
146234
tableRows,
147235
columnData,
148236
isFileSize,
237+
isTimeSort,
149238
isDataAttribute,
150239
colSpanData,
151240
colSpanSum,
@@ -165,7 +254,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
165254
if (isFileSize) {
166255
fileSizeColumnTextAndRow[columnData[i]] = tr.innerHTML;
167256
}
168-
if (!isFileSize && !isDataAttribute) {
257+
if (!isFileSize && !isDataAttribute && !isTimeSort) {
169258
columnData.push(`${tdTextContent}#${i}`);
170259
columnIndexAndTableRow[`${tdTextContent}#${i}`] = tr.innerHTML;
171260
}
@@ -301,6 +390,11 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
301390
sortFileSize(visibleTableRows, columnData);
302391
}
303392

393+
const isTimeSort = th.classList.contains("runtime-sort");
394+
if (isTimeSort) {
395+
sortByRuntime(visibleTableRows, columnData);
396+
}
397+
304398
const isRememberSort = sortableTable.classList.contains("remember-sort");
305399
if (!isRememberSort) {
306400
rememberSort(timesClickedColumn, columnIndexesClicked);
@@ -314,12 +408,17 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
314408
columnData,
315409
isFileSize,
316410
isDataAttribute,
411+
isTimeSort,
317412
colSpanData,
318413
colSpanSum,
319414
};
320415
getTableData(tableProperties);
321416
updateTable(tableProperties);
322417
});
418+
let isOnloadSort = th.classList.contains("onload-sort");
419+
if (isOnloadSort) {
420+
th.click();
421+
}
323422
}
324423
}
325424

npm/README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ Refer to the documenation for examples on how to use table-sort-js with [HTML](h
4141

4242
#### Classes:
4343

44-
| <table> classes | Description |
45-
| --------------------- | ----------------------------------------------------------------------- |
46-
| "table-sort" | Make the table sortable! (Words, numbers, dates) |
47-
| "table-arrows" | Display ascending or descending triangles. |
48-
| "remember-sort" | If clicking on different columns remembers sort of the original column. |
44+
| <table> classes | Description |
45+
| --------------------- | -------------------------------------------------------------------------------------------- |
46+
| "table-sort" | Make the table sortable! (Words, numbers)... |
47+
| "table-arrows" | Display ascending or descending triangles. |
48+
| "no-class-infer" | Turns off inference for adding sort classes automatically (file-size-sort and runtime-sort). |
49+
| "remember-sort" | If clicking on different columns remembers sort of the original column. |
4950

5051
| <th> classes | Description |
5152
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |

npm/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "table-sort-js",
3-
"version": "1.11.2",
3+
"version": "1.12.0",
44
"description": "A JavaScript client-side HTML table sorting library with no dependencies required.",
55
"license": "MIT",
66
"repository": "LeeWannacott/table-sort-js",

npm/table-sort.js

+63-7
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,64 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
5959
}
6060
}
6161

62+
function addInferredClass(th, columnLength, currentCount, classToAdd) {
63+
const threshold = columnLength / 2;
64+
if (currentCount >= threshold) {
65+
th.classList.add(classToAdd);
66+
}
67+
}
68+
69+
function inferSortClasses(tableRows, tableHeadHeaders) {
70+
for (let [columnIndex, th] of tableHeadHeaders.entries()) {
71+
const regexMinutesAndSeconds = /^(\d+h)?\s?(\d+m)?\s?(\d+s)?$/i;
72+
const regexFileSizeSort = /^([.0-9]+)\s?(B|KB|KiB|MB|MiB|GB|GiB|TB|TiB)/i;
73+
let runtimeSortCounter = 0,
74+
fileSizeSortCounter = 0;
75+
76+
let tableColumnLength = th.parentElement.childElementCount;
77+
for (let tr of tableRows) {
78+
let runtimeSortMatch, fileSizeSortMatch;
79+
const tableColumn = tr.querySelectorAll("td").item(columnIndex);
80+
if (tableColumn.innerText) {
81+
runtimeSortMatch = tableColumn.innerText.match(
82+
regexMinutesAndSeconds
83+
);
84+
fileSizeSortMatch = tableColumn.innerText.match(regexFileSizeSort);
85+
}
86+
if (runtimeSortMatch) {
87+
runtimeSortCounter++;
88+
}
89+
if (fileSizeSortMatch) {
90+
fileSizeSortCounter++;
91+
}
92+
}
93+
// TODO: refactor this into one function called addInferredClasses that loops over sort classes and counters
94+
addInferredClass(
95+
th,
96+
tableColumnLength,
97+
runtimeSortCounter,
98+
"runtime-sort"
99+
);
100+
addInferredClass(
101+
th,
102+
tableColumnLength,
103+
fileSizeSortCounter,
104+
"file-size-sort"
105+
);
106+
}
107+
}
108+
62109
function makeTableSortable(sortableTable) {
63110
const tableBody = getTableBody(sortableTable);
64111
const tableHead = sortableTable.querySelector("thead");
65112
const tableHeadHeaders = tableHead.querySelectorAll("th");
113+
const tableRows = tableBody.querySelectorAll("tr");
114+
115+
const isNoSortClassInference =
116+
sortableTable.classList.contains("no-class-infer");
117+
if (!isNoSortClassInference) {
118+
inferSortClasses(tableRows, tableHeadHeaders);
119+
}
66120

67121
for (let [columnIndex, th] of tableHeadHeaders.entries()) {
68122
if (!th.classList.contains("disable-sort")) {
@@ -124,24 +178,26 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
124178

125179
function sortByRuntime(tableRows, columnData) {
126180
for (let [i, tr] of tableRows.entries()) {
127-
const regexMinutesAndSeconds = /^(\d+m)\s?(\d+s)$/i;
181+
const regexMinutesAndSeconds = /^(\d+h)?\s?(\d+m)?\s?(\d+s)?$/i;
128182
let columnOfTd = tr
129183
.querySelectorAll("td")
130184
.item(columnIndex).textContent;
131185
let match = columnOfTd.match(regexMinutesAndSeconds);
132-
let minutesInSeconds,
133-
seconds,
134-
timeinSeconds = [0, 0, 0];
186+
let [minutesInSeconds, hours, seconds, timeinSeconds] = [0, 0, 0, 0];
135187
if (match) {
136-
const regexMinutes = match[1];
188+
const regexHours = match[1];
189+
if (regexHours) {
190+
hours = Number(regexHours.replace("h", "")) * 60 * 60;
191+
}
192+
const regexMinutes = match[2];
137193
if (regexMinutes) {
138194
minutesInSeconds = Number(regexMinutes.replace("m", "")) * 60;
139195
}
140-
const regexSeconds = match[2];
196+
const regexSeconds = match[3];
141197
if (regexSeconds) {
142198
seconds = Number(regexSeconds.replace("s", ""));
143199
}
144-
timeinSeconds = minutesInSeconds + seconds;
200+
timeinSeconds = hours + minutesInSeconds + seconds;
145201
}
146202
columnData.push(`${timeinSeconds}#${i}`);
147203
columnIndexAndTableRow[columnData[i]] = tr.innerHTML;

public/index.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h1>Testing table sort js</h1>
1010
<table class="table-sort table-arrows">
1111
<thead>
1212
<tr>
13-
<th >Last Name</th>
13+
<th>Last Name</th>
1414
<th>First Name</th>
1515
<th class="order-by-desc">Birth Date</th>
1616
<th>Employee ID</th>

test/table.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const tableSortJs = require("../public/table-sort");
77
function createTestTable(
88
testTableData,
99
thAttributes = { classTags: "", colspan: "" },
10-
props = { colsToClick: [], invisibleIndex: [] ,tableTags:""}
10+
props = { colsToClick: [], invisibleIndex: [], tableTags: "" }
1111
) {
1212
const numberOfTableColumns = Object.keys(testTableData).length;
1313
let testTableHeaders = "";

0 commit comments

Comments
 (0)