From 2e93b276bd4abb247005d914f8b51d1f242a847b Mon Sep 17 00:00:00 2001 From: Lee Wannacott Date: Fri, 12 May 2023 16:10:18 +1200 Subject: [PATCH] Feature: dates-ymd-sort iso 8061 yyyy/mm/dd sort! :=) (#85) * Implemented iso 8061 yyyy/mm/dd sort! :=) * Refactor: dateSort to be less verbose. * Remove iso date inference with . delim as could be decimal etc... * Update docs for yyyy/mm/dd ISO date. --- README.md | 27 ++++++++-------- public/index.html | 4 +-- public/table-sort.js | 77 ++++++++++++++++++++++++-------------------- test/table.test.js | 13 ++++++++ 4 files changed, 71 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 0ccec72..6e36cf8 100644 --- a/README.md +++ b/README.md @@ -45,22 +45,23 @@ Refer to the documenation for examples on how to use table-sort-js with [HTML](h | <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). | +| "table-arrows" | Display ascending or descending triangles. | | "remember-sort" | If clicking on different columns remembers sort of the original column. | -| <th> classes | Description | -| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | -| "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) | -| "disable-sort" | Disallow sorting the table by this specific column. | -| "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 | Description | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | +| "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"> | +| "dates-mdy-sort" | Sorts dates in US style mm/dd/yyyy format;. e.g (12/28/2023). Can use "/" or "-" as separator. Overides inferred "dates-dmy-sort" class. | +| "onload-sort" | Sort column on loading of the page. Simulates a click from the user. (can only sort onload for one column) | +| "disable-sort" | Disallow sorting the table by this specific column. | + +| <th> Inferred Classes. | Description | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| "dates-dmy-sort" | Sorts dates in dd/mm/yyyy format. e.g (18/10/1995). Can use "/" or "-" as separator. | +| "dates-ymd-sort" | Sorts dates in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) yyyy/mm/dd format. e.g (2021/10/28). Use "/" or "-" as separator. | +| "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) | +| "runtime-sort" | Sorts runtime in hours minutes and seconds e.g (10h 1m 20s). Useful for sorting the GitHub actions Run time column... | | <th> Classes that change defaults. | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | diff --git a/public/index.html b/public/index.html index b8660ab..fc7c5ec 100644 --- a/public/index.html +++ b/public/index.html @@ -23,7 +23,7 @@

Manual testing of table sort js

Franklin Benjamin - 1706,1,17 + 1706/1/17 1 k-level 1h 1m 17s @@ -33,7 +33,7 @@

Manual testing of table sort js

da Vinci Zarlo - 1452.4.15 + 1452-4-15 13000 1m 45s diff --git a/public/table-sort.js b/public/table-sort.js index 95f4b2a..e619beb 100644 --- a/public/table-sort.js +++ b/public/table-sort.js @@ -71,49 +71,51 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { 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; // Doesn't infer dates with delimiter "."; as could capture semantic version numbers. - const regexDates = /^(\d\d?)[/-](\d\d?)[/-]((\d\d)?\d\d)$/; - let runtimeSortCounter = 0, - fileSizeSortCounter = 0, - datesSortCounter = 0; + const datesRegex = /^(\d\d?)[/-](\d\d?)[/-]((\d\d)?\d\d)/; + const regexISODates = /^(\d\d\d\d)[/-](\d\d?)[/-](\d\d?)/; + let runtimeCounter = 0, + fileSizeCounter = 0, + datesCounter = 0, + isoDatesCounter = 0; let tableColumnLength = th.parentElement.childElementCount; for (let tr of tableRows) { - let runtimeSortMatch, fileSizeSortMatch, datesSortMatch; + let runtimeSortMatch, fileSizeSortMatch, datesMatch, isoDatesMatch; 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); + datesMatch = tableColumn.innerText.match(datesRegex); + isoDatesMatch = tableColumn.innerText.match(regexISODates); } if (runtimeSortMatch) { - runtimeSortCounter++; + runtimeCounter++; } if (fileSizeSortMatch) { - fileSizeSortCounter++; + fileSizeCounter++; } - if (datesSortMatch) { - datesSortCounter++; + if (datesMatch) { + datesCounter++; + } + if (isoDatesMatch) { + isoDatesCounter++; } } // TODO: refactor this into one function called addInferredClasses that loops over sort classes and counters + addInferredClass(th, tableColumnLength, runtimeCounter, "runtime-sort"); addInferredClass( th, tableColumnLength, - runtimeSortCounter, - "runtime-sort" - ); - addInferredClass( - th, - tableColumnLength, - fileSizeSortCounter, + fileSizeCounter, "file-size-sort" ); + addInferredClass(th, tableColumnLength, datesCounter, "dates-dmy-sort"); addInferredClass( th, tableColumnLength, - datesSortCounter, - "dates-dmy-sort" + isoDatesCounter, + "dates-ymd-sort" ); } } @@ -227,31 +229,30 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { } } - function sortDates(dateFormat, tableRows, columnData) { + function sortDates(datesFormat, tableRows, columnData) { try { for (let [i, tr] of tableRows.entries()) { - let columnOfTd; - const regexDates = /^(\d\d?)[./-](\d\d?)[./-]((\d\d)?\d\d)$/; + let columnOfTd, datesRegex; + if (datesFormat === "mdy" || datesFormat === "dmy") { + datesRegex = /^(\d\d?)[./-](\d\d?)[./-]((\d\d)?\d\d)/; + } else if (datesFormat === "ymd") { + datesRegex = /^(\d\d\d\d)[./-](\d\d?)[./-](\d\d?)/; + } columnOfTd = tr.querySelectorAll("td").item(columnIndex).textContent; - let match = columnOfTd.match(regexDates); + let match = columnOfTd.match(datesRegex); 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; + const [regPos1, regPos2, regPos3] = [match[1], match[2], match[3]]; + if (regPos1 && regPos2 && regPos3) { + if (datesFormat === "mdy") { + [months, days, years] = [regPos1, regPos2, regPos3]; + } else if (datesFormat === "ymd") { + [years, months, days] = [regPos1, regPos2, regPos3]; } else { - days = regexFirstNumber; - months = regexSecondNumber; + [days, months, years] = [regPos1, regPos2, regPos3]; } } - if (regexYears) { - years = regexYears; - } numberToSort = Number( years + String(months).padStart(2, "0") + @@ -299,6 +300,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { isTimeSort, isSortDateDayMonthYear, isSortDateMonthDayYear, + isSortDateYearMonthDay, isDataAttribute, colSpanData, colSpanSum, @@ -324,6 +326,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { !isDataAttribute && !isTimeSort && !isSortDateDayMonthYear && + !isSortDateYearMonthDay && !isSortDateMonthDayYear ) { columnData.push(`${tdTextContent}#${i}`); @@ -468,9 +471,12 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { const isSortDateDayMonthYear = th.classList.contains("dates-dmy-sort"); const isSortDateMonthDayYear = th.classList.contains("dates-mdy-sort"); + const isSortDateYearMonthDay = th.classList.contains("dates-ymd-sort"); // pick mdy first to override the inferred default class which is dmy. if (isSortDateMonthDayYear) { sortDates("mdy", visibleTableRows, columnData); + } else if (isSortDateYearMonthDay) { + sortDates("ymd", visibleTableRows, columnData); } else if (isSortDateDayMonthYear) { sortDates("dmy", visibleTableRows, columnData); } @@ -489,6 +495,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { isFileSize, isSortDateDayMonthYear, isSortDateMonthDayYear, + isSortDateYearMonthDay, isDataAttribute, isTimeSort, colSpanData, diff --git a/test/table.test.js b/test/table.test.js index e0a5f77..62ef9b3 100644 --- a/test/table.test.js +++ b/test/table.test.js @@ -352,3 +352,16 @@ test("dates-mdy-sort: US style mm/dd/yyyy; delim . or / or -", () => { ], }); }); + +test("dates-ymd-sort: ISO 8601 style yyyy/mm/dd; delim . or / or -", () => { + expect( + createTestTable( + { + col0: ["2023/09/6", "2023-03-9", "2023.12.16", "2023/4/6", "2023/4/32"], + }, + { classTags: "dates-ymd-sort" } + ) + ).toStrictEqual({ + col0: ["2023-03-9", "2023/4/6", "2023/4/32", "2023/09/6", "2023.12.16"], + }); +});