diff --git a/README.md b/README.md index 445219c..977f0cc 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ Refer to the documenation for examples on how to use table-sort-js with [HTML](h | "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 10 B, 100 KiB, 1 MiB); optional space between number and prefix. | | "runtime-sort" | Sorts runtime in hours minutes and seconds e.g (10h 1m 20s). Useful for sorting the GitHub actions Run time column... | +| "numeric-sort" | Sorts numbers - Positive, Negative (Both minus and parenthesis representations), and Decimals | | <th> Classes that change defaults. | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | diff --git a/public/table-sort.js b/public/table-sort.js index 238cb60..eaf9bcd 100644 --- a/public/table-sort.js +++ b/public/table-sort.js @@ -65,11 +65,13 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { // Doesn't infer dates with delimiter "."; as could capture semantic version numbers. const dmyRegex = /^(\d\d?)[/-](\d\d?)[/-]((\d\d)?\d\d)/; const ymdRegex = /^(\d\d\d\d)[/-](\d\d?)[/-](\d\d?)/; + const numericRegex = /^(?:\(\d+(?:\.\d+)?\)|-?\d+(?:\.\d+)?)$/; const inferableClasses = { runtime: { regexp: runtimeRegex, class: "runtime-sort", count: 0 }, filesize: { regexp: fileSizeRegex, class: "file-size-sort", count: 0 }, dmyDates: { regexp: dmyRegex, class: "dates-dmy-sort", count: 0 }, ymdDates: { regexp: ymdRegex, class: "dates-ymd-sort", count: 0 }, + numericRegex: {regexp: numericRegex, class: "numeric-sort",count:0} }; let classNameAdded = false; let regexNotFoundCount = 0; @@ -335,17 +337,48 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) { const isPunctSort = th.classList.contains("punct-sort"); const isAlphaSort = th.classList.contains("alpha-sort"); + const isNumericSort = th.classList.contains("numeric-sort"); + + function parseNumberFromString(str) { + let num; + str = str.slice(0, str.indexOf("#")); + if (str.match(/^\((\d+(?:\.\d+)?)\)$/)) { + num = -1 * Number(str.slice(1, -1)); + } else { + num = Number(str); + } + return num; + } + + function strLocaleCompare(str1, str2) { + return str1.localeCompare( + str2, + navigator.languages[0] || navigator.language, + { numeric: !isAlphaSort, ignorePunctuation: !isPunctSort } + ); + } + + function handleNumbers(str1, str2) { + let num1, num2; + num1 = parseNumberFromString(str1); + num2 = parseNumberFromString(str2); + + if (!isNaN(num1) && !isNaN(num2)) { + return num1 - num2; + } else { + return strLocaleCompare(str1, str2); + } + } + function sortAscending(a, b) { if (a.includes(`${fillValue}#`)) { return 1; } else if (b.includes(`${fillValue}#`)) { return -1; + } else if (isNumericSort) { + return handleNumbers(a, b); } else { - return a.localeCompare( - b, - navigator.languages[0] || navigator.language, - { numeric: !isAlphaSort, ignorePunctuation: !isPunctSort } - ); + return strLocaleCompare(a, b); } } diff --git a/test/table.test.js b/test/table.test.js index a374010..32b7c6e 100644 --- a/test/table.test.js +++ b/test/table.test.js @@ -489,3 +489,42 @@ test("dates-ymd-sort: ISO 8601 style yyyy/mm/dd; delim . or / or -", () => { col0: ["2023-03-9", "2023/4/6", "2023/4/32", "2023/09/6", "2023.12.16"], }); }); + +test("Sort decimal numbers", () => { + expect( + createTestTable( + { + col0: ["0.1", "0.2", "0.3", "0.11", "0.13", "0.13", "0.14"], + }, + { classTags: "numeric-sort" } + ) + ).toStrictEqual({ + col0: ["0.1", "0.11", "0.13", "0.13", "0.14", "0.2", "0.3"], + }); +}); + +test("Sort all combination positive, negative numbers with parenthesis as well", () => { + expect( + createTestTable( + { + col0: ["1.05", "-2.3", "-3", "1", "-6", "(1.4)", "14"], + }, + { classTags: "numeric-sort" } + ) + ).toStrictEqual({ + col0: ["-6","-3","-2.3","(1.4)","1","1.05","14"], + }); +}); + +test("Sort all combination of negative and positive integers and decimal numbers and even alphabetical random", () => { + expect( + createTestTable( + { + col0: ["1.05", "-2.3", "-3", "1", "-6", "","(0.5)","1a","b","(c)","{1}"], + }, + { classTags: "numeric-sort" } + ) + ).toStrictEqual({ + col0: ["-6","-3","-2.3","(0.5)","1","1.05","{1}","1a","b","(c)",""], + }); +}); \ No newline at end of file