diff --git a/README.md b/README.md index fd46c91..0ccec72 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ 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-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. | @@ -57,10 +57,10 @@ Refer to the documenation for examples on how to use table-sort-js with [HTML](h | "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) | +| ---------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| "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 | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | diff --git a/browser-extension/manifest.json b/browser-extension/manifest.json index 78c5958..b6ceac0 100644 --- a/browser-extension/manifest.json +++ b/browser-extension/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "author": "Lee Wannacott", "name": "table-sort-js", - "version": "1.12.1", + "version": "1.13.0", "description": "Makes tables sortable using table-sort-js: https://github.com/LeeWannacott/table-sort-js", "icons": { "48": "icons/t.png" }, "browser_action": { diff --git a/browser-extension/table-sort.js b/browser-extension/table-sort.js index 660bffc..9e6e00b 100644 --- a/browser-extension/table-sort.js +++ b/browser-extension/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/npm/README.md b/npm/README.md index 69d7f5b..0ccec72 100644 --- a/npm/README.md +++ b/npm/README.md @@ -12,6 +12,7 @@ - [Documentation.](https://leewannacott.github.io/table-sort-js/docs/about.html) (work in progress) - [npm package.](https://www.npmjs.com/package/table-sort-js) +- [firefox browser extension](https://addons.mozilla.org/en-US/firefox/addon/table-sort-js/) ## Install instructions. @@ -41,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/npm/package.json b/npm/package.json index 6bf0c34..850be13 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "table-sort-js", - "version": "1.12.1", + "version": "1.13.0", "description": "A JavaScript client-side HTML table sorting library with no dependencies required.", "license": "MIT", "repository": "LeeWannacott/table-sort-js", diff --git a/npm/table-sort.js b/npm/table-sort.js index 660bffc..9e6e00b 100644 --- a/npm/table-sort.js +++ b/npm/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/package.json b/package.json index 3c9c235..b82baa9 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,11 @@ "extends": "react-app" }, "browserslist": { - "production": [">0.2%", "not dead", "not op_mini all"], + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], "development": [ "last 1 chrome version", "last 1 firefox version",