From b33d3c31c30f4bae87a7faaa4d00c1ff08522c0b Mon Sep 17 00:00:00 2001 From: Lee Wannacott Date: Thu, 11 May 2023 18:33:02 +1200 Subject: [PATCH] Sort dates with dates-dmy-sort dd/mm/yyyy and dates-mdy-sort mm/dd/yyyy (#84) * WIP 1: sort dates... * WIP 2: sort dates...; might need separate class for metric and imperial... * WIP 4 pretty much done need to figure out differentation for US mm/dd/yyyy vs rest of world dd/mm/yyyy. * date-dmy-sort and date-dmy-sort completed tests written and readme updated --- README.md | 30 ++++++++++------ deploy.sh | 3 +- public/index.html | 18 ++++++---- public/table-sort.js | 81 +++++++++++++++++++++++++++++++++++++++++--- test/table.test.js | 62 ++++++++++++++++++++++++++++++++- 5 files changed, 170 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index db31fba..fd46c91 100644 --- a/README.md +++ b/README.md @@ -42,23 +42,31 @@ Refer to the documenation for examples on how to use table-sort-js with [HTML](h #### Classes: -| <table> classes | Description | -| --------------------- | -------------------------------------------------------------------------------------------- | -| "table-sort" | Make the table sortable! (Words, numbers)... | -| "table-arrows" | Display ascending or descending triangles. | -| "no-class-infer" | Turns off inference for adding sort classes automatically (file-size-sort and runtime-sort). | -| "remember-sort" | If clicking on different columns remembers sort of the original column. | +| <table> classes | Description | +| --------------------- | ------------------------------------------------------------------------------------------------------------- | +| "table-sort" | Make the table sortable! (Words, numbers, dates, file sizes)... | +| "table-arrows" | Display ascending or descending triangles. | +| "no-class-infer" | Turns off inference for adding sort classes automatically i.e (file-size-sort, runtime-sort, dates-dmy-sort). | +| "remember-sort" | If clicking on different columns remembers sort of the original column. | | <th> classes | Description | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | -| "order-by-desc" | Order by descending on first click. (default is aescending) | | "data-sort" | Sort by [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes), e.g <td data-sort="42"> | | "onload-sort" | Sort column on loading of the page. Simulates a click from the user. (can only sort onload for one column) | -| "file-size-sort" | Sort file sizes(B->TiB) uses the binary prefix. (e.g KiB) | -| "runtime-sort" | Sorts runtime in minutes and seconds e.g (1m 20s). Useful for sorting the GitHub actions Run time column... | | "disable-sort" | Disallow sorting the table by this specific column. | -| "alpha-sort" | Sort alphabetically (z11,z2); default is [natural sort](https://en.wikipedia.org/wiki/Natural_sort_order) (z2,z11). | -| "punct-sort" | Sort punctuation; default ignores punctuation. | +| "dates-mdy-sort" | Sorts dates in mm/dd/yyyy format. e.g (12/28/2023). Can use "/" or "-" or "." as separator. Overides inferred "dates-dmy-sort" class. | + +| <th> Inferred Classes. | Description | +| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| "dates-dmy-sort" | Sorts dates in dd/mm/yyyy format. e.g (18/10/1995). Can use "/" or "-" or "." as separator. | +| "runtime-sort" | Sorts runtime in hours minutes and seconds e.g (10h 1m 20s). Useful for sorting the GitHub actions Run time column... | +| "file-size-sort" | Sorts file sizes(B->TiB) uses the binary prefix. (e.g KiB). Input data ideally in Bytes e.g (10b or 10B) | + +| <th> Classes that change defaults. | Description | +| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| "order-by-desc" | Order by descending on first click. (default is aescending) | +| "alpha-sort" | Sort alphabetically (z11,z2); default is [natural sort](https://en.wikipedia.org/wiki/Natural_sort_order) (z2,z11). | +| "punct-sort" | Sort punctuation; default ignores punctuation. | #### Development: diff --git a/deploy.sh b/deploy.sh index 993416c..b97ce39 100755 --- a/deploy.sh +++ b/deploy.sh @@ -6,4 +6,5 @@ cp Contributors.md npm/Contributors.md npx prettier --write . npm run deploy npm run test -echo "Reminder: Update npm package to new version in npm/package.json and npm publish" +echo "Reminder: Update npm package to new version in npm/package.json and npm publish." +echo "Reminder: Update firefox browser extension manifest." diff --git a/public/index.html b/public/index.html index c8a46e5..b8660ab 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,7 @@
-

Testing table sort js

+

Manual testing of table sort js

@@ -17,43 +17,48 @@

Testing table sort js

+ - + - + + - + + - + + - + + @@ -64,6 +69,7 @@

Testing table sort js

+
Department Runtime File Sizedates in dd/mm/yyyy
FranklinbenjaminBenjamin 1706,1,171 k-level 1h 1m 17s 10b17/6/1978
da Vinci Zarlo 1452.4.1513000 1m 45s 192038998987021b18/10/2027
StathamJason 1967-7-26 HR 11m 40s 134809b4/9/2008
MichealAngelo 1958/8/21 54 Marketing 29s 30980980b2/3/1879
Marketing 41s 902938402398b8/6/1978
diff --git a/public/table-sort.js b/public/table-sort.js index 660bffc..9e6e00b 100644 --- a/public/table-sort.js +++ b/public/table-sort.js @@ -70,18 +70,20 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { for (let [columnIndex, th] of tableHeadHeaders.entries()) { const regexMinutesAndSeconds = /^(\d+h)?\s?(\d+m)?\s?(\d+s)?$/i; const regexFileSizeSort = /^([.0-9]+)\s?(B|KB|KiB|MB|MiB|GB|GiB|TB|TiB)/i; + const regexDates = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; let runtimeSortCounter = 0, - fileSizeSortCounter = 0; - + fileSizeSortCounter = 0, + datesSortCounter = 0; let tableColumnLength = th.parentElement.childElementCount; for (let tr of tableRows) { - let runtimeSortMatch, fileSizeSortMatch; + let runtimeSortMatch, fileSizeSortMatch, datesSortMatch; const tableColumn = tr.querySelectorAll("td").item(columnIndex); if (tableColumn.innerText) { runtimeSortMatch = tableColumn.innerText.match( regexMinutesAndSeconds ); fileSizeSortMatch = tableColumn.innerText.match(regexFileSizeSort); + datesSortMatch = tableColumn.innerText.match(regexDates); } if (runtimeSortMatch) { runtimeSortCounter++; @@ -89,6 +91,9 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { if (fileSizeSortMatch) { fileSizeSortCounter++; } + if (datesSortMatch) { + datesSortCounter++; + } } // TODO: refactor this into one function called addInferredClasses that loops over sort classes and counters addInferredClass( @@ -103,6 +108,12 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { fileSizeSortCounter, "file-size-sort" ); + addInferredClass( + th, + tableColumnLength, + datesSortCounter, + "dates-dmy-sort" + ); } } @@ -190,7 +201,8 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { columnOfTd = tr.querySelectorAll("td").item(columnIndex).innerText; } let match = columnOfTd.match(regexMinutesAndSeconds); - let [minutesInSeconds, hours, seconds, timeinSeconds] = [0, 0, 0, 0]; + let [minutesInSeconds, hours, seconds] = [0, 0, 0]; + let timeinSeconds = columnOfTd; if (match) { const regexHours = match[1]; if (regexHours) { @@ -214,6 +226,45 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { } } + function sortDates(dateFormat, tableRows, columnData) { + try { + for (let [i, tr] of tableRows.entries()) { + let columnOfTd; + const regexDate = /^(\d\d?)[./-](\d\d?)[./-]((\d\d)?\d\d)$/; + columnOfTd = tr.querySelectorAll("td").item(columnIndex).textContent; + let match = columnOfTd.match(regexDate); + let [years, days, months] = [0, 0, 0]; + let numberToSort = columnOfTd; + if (match) { + const regexFirstNumber = match[1]; + const regexSecondNumber = match[2]; + const regexYears = match[3]; + if (regexFirstNumber && regexSecondNumber) { + if (dateFormat === "mdy") { + days = regexSecondNumber; + months = regexFirstNumber; + } else { + days = regexFirstNumber; + months = regexSecondNumber; + } + } + if (regexYears) { + years = regexYears; + } + numberToSort = Number( + years + + String(months).padStart(2, "0") + + String(days).padStart(2, "0") + ); + } + columnData.push(`${numberToSort}#${i}`); + columnIndexAndTableRow[columnData[i]] = tr.innerHTML; + } + } catch (e) { + console.log(e); + } + } + let [timesClickedColumn, columnIndexesClicked] = [0, []]; function rememberSort(timesClickedColumn, columnIndexesClicked) { @@ -245,6 +296,8 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { columnData, isFileSize, isTimeSort, + isSortDateDayMonthYear, + isSortDateMonthDayYear, isDataAttribute, colSpanData, colSpanSum, @@ -264,7 +317,14 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { if (isFileSize) { fileSizeColumnTextAndRow[columnData[i]] = tr.innerHTML; } - if (!isFileSize && !isDataAttribute && !isTimeSort) { + // These classes already handle pushing to column and setting the tr html. + if ( + !isFileSize && + !isDataAttribute && + !isTimeSort && + !isSortDateDayMonthYear && + !isSortDateMonthDayYear + ) { columnData.push(`${tdTextContent}#${i}`); columnIndexAndTableRow[`${tdTextContent}#${i}`] = tr.innerHTML; } @@ -405,6 +465,15 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { sortByRuntime(visibleTableRows, columnData); } + const isSortDateDayMonthYear = th.classList.contains("dates-dmy-sort"); + const isSortDateMonthDayYear = th.classList.contains("dates-mdy-sort"); + // pick mdy first to override the inferred default class which is dmy. + if (isSortDateMonthDayYear) { + sortDates("mdy", visibleTableRows, columnData); + } else if (isSortDateDayMonthYear) { + sortDates("dmy", visibleTableRows, columnData); + } + const isRememberSort = sortableTable.classList.contains("remember-sort"); if (!isRememberSort) { rememberSort(timesClickedColumn, columnIndexesClicked); @@ -417,6 +486,8 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { tableRows: visibleTableRows, columnData, isFileSize, + isSortDateDayMonthYear, + isSortDateMonthDayYear, isDataAttribute, isTimeSort, colSpanData, diff --git a/test/table.test.js b/test/table.test.js index 74cd6f9..e0a5f77 100644 --- a/test/table.test.js +++ b/test/table.test.js @@ -251,7 +251,7 @@ test("Clicking multiple times (>2) doesn't break sorting", () => { }); }); -test("time-sort class", () => { +test("runtime-sort", () => { expect( createTestTable( { @@ -292,3 +292,63 @@ test("time-sort class", () => { ], }); }); + +test("dates-dmy-sort: UK style dd/mm/yyyy; delim . or / or -", () => { + expect( + createTestTable( + { + col0: [ + "17/6/1978", + "18.10.2027", + "10-12-2017", + "13/12/2017", + "4.9.2008", + "2.3.1879", + "22.3.1879", + "8/6/1978", + "4/6/1978", + ], + }, + { classTags: "dates-dmy-sort" } + ) + ).toStrictEqual({ + col0: [ + "2.3.1879", + "22.3.1879", + "4/6/1978", + "8/6/1978", + "17/6/1978", + "4.9.2008", + "10-12-2017", + "13/12/2017", + "18.10.2027", + ], + }); +}); + +test("dates-mdy-sort: US style mm/dd/yyyy; delim . or / or -", () => { + expect( + createTestTable( + { + col0: [ + "1-14-1992", + "1.13.1992", + "4.30.2008", + "1/20/1992", + "10-12-2017", + "2/14/1992", + ], + }, + { classTags: "dates-mdy-sort" } + ) + ).toStrictEqual({ + col0: [ + "1.13.1992", + "1-14-1992", + "1/20/1992", + "2/14/1992", + "4.30.2008", + "10-12-2017", + ], + }); +});