Skip to content

Commit

Permalink
Handle common currencies ($£€¥) with numeric-sort class. (#132)
Browse files Browse the repository at this point in the history
* Handle common currencies and negatives.

* Prettify files.

* Add bitcoin and ethereum currency signs.

* Update readme to say numeric-sort now supports currency
  • Loading branch information
LeeWannacott authored Mar 30, 2024
1 parent a510eb2 commit 8f38e5f
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 122 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Examples on using table-sort-js with frontend frameworks such as [React.js](http

| <th> Inferred Classes. | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| "numeric-sort" | Sorts numbers including decimals - Positive, Negative (in both minus and parenthesis representations) |
| "numeric-sort" | Sorts numbers including decimals - Positive, Negative (in both minus and parenthesis representations). Supports for common currencies e.g ($£€¥) |
| "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 10 B, 100 KiB, 1 MiB); optional space between number and prefix. |
Expand Down
16 changes: 8 additions & 8 deletions public/table-sort.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
// Don'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+)?)$/; doesn't handle commas
const numericRegex =
/^-?(?:\d{1,3}(?:[',]\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?(?:[',]\d{3})*?)$/;
/^-?(?:[$£€¥₩₽₺₣฿₿Ξξ¤¿\u20A1\uFFE0]\d{1,3}(?:[',]\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?(?:[',]\d{3})*?)$/;


const inferableClasses = {
runtime: { regexp: runtimeRegex, class: "runtime-sort", count: 0 },
filesize: { regexp: fileSizeRegex, class: "file-size-sort", count: 0 },
Expand Down Expand Up @@ -342,7 +343,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
function parseNumberFromString(str) {
let num;
str = str.slice(0, str.indexOf("#"));
if (str.match(/^\((\d+(?:\.\d+)?)\)$/)) {
if (str.match(/^\(-?(\d+(?:\.\d+)?)\)$/)) {
num = -1 * Number(str.slice(1, -1));
} else {
num = Number(str);
Expand All @@ -359,11 +360,10 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
}

function handleNumbers(str1, str2) {
let num1, num2;
str1 = str1.replaceAll(",", "");
str2 = str2.replaceAll(",", "");
num1 = parseNumberFromString(str1);
num2 = parseNumberFromString(str2);
const currencyAndComma = /[$£€¥₩₽₺₣฿₿Ξξ¤¿\u20A1\uFFE0, ]/g
str1 = str1.replace(currencyAndComma, "");
str2 = str2.replace(currencyAndComma, "");
const [num1, num2] = [parseNumberFromString(str1),parseNumberFromString(str2)];

if (!isNaN(num1) && !isNaN(num2)) {
return num1 - num2;
Expand Down
53 changes: 53 additions & 0 deletions test/table.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,59 @@ test("Sort all combination of negative and positive integers and decimal numbers
});
});

test("numeric-sort - various currency", () => {
expect(
createTestTable(
{
col0: {
td: [
"-$4.01",
"-¥2.02",
"($5.03)",
"$4.64",
"-£29,675",
"-$5.21",
"-£50,854",
"£2,038,720",
"£283,838,720",
"-£481,177",
"$2.01",
"$2.11",
"฿2.21",
"-£1,976,799",
"£2,265",
"(£420,252)",
"-€2,409,060",
"-£755,905",
],
},
},
{ classTags: "numeric-sort" }
)
).toStrictEqual({
col0: [
"-€2,409,060",
"-£1,976,799",
"-£755,905",
"-£481,177",
"(£420,252)",
"-£50,854",
"-£29,675",
"-$5.21",
"($5.03)",
"-$4.01",
"-¥2.02",
"$2.01",
"$2.11",
"฿2.21",
"$4.64",
"£2,265",
"£2,038,720",
"£283,838,720",
],
});
});

test("default behavior without cells-sort (tr's move when sorted)", () => {
expect(
createTestTable(
Expand Down
7 changes: 4 additions & 3 deletions test/tagsInferenceTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ function createTestTable(
tableSortJs(true, dom.window.document);
// Make an array from table contents to test if sorted correctly.
let table = dom.window.document.querySelector("table");
const tableHeadWithInferredClassName = table
.querySelectorAll("thead th")
let inferedClassNamesOfTh = Array.from(tableHeadWithInferredClassName).map((e)=>e.getAttribute("class"))
const tableHeadWithInferredClassName = table.querySelectorAll("thead th");
let inferedClassNamesOfTh = Array.from(tableHeadWithInferredClassName).map(
(e) => e.getAttribute("class")
);
return inferedClassNamesOfTh;
}

Expand Down
217 changes: 107 additions & 110 deletions test/tagsInferenceTable.test.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,39 @@
const createTestTable = require("./tagsInferenceTable");


test("InferSortClassesOnTH - FILE SIZE", () => {
expect(
createTestTable({
col0: {
td: [
"10MB",
"10GB",
"10TB",
"10B",
"10MiB",
"10TiB",
"10Kib",
"10KB",
"10GiB",
],
},
// add in space and make some undercase
col1: {
td: [
"10 mB",
"10 GB",
"10 Tb",
"10 B",
"10 mib",
"10 tib",
"10 kib",
"10 kB",
"10 giB",
],
},
col0: {
td: [
"10MB",
"10GB",
"10TB",
"10B",
"10MiB",
"10TiB",
"10Kib",
"10KB",
"10GiB",
],
},
// add in space and make some undercase
col1: {
td: [
"10 mB",
"10 GB",
"10 Tb",
"10 B",
"10 mib",
"10 tib",
"10 kib",
"10 kB",
"10 giB",
],
},
})
).toStrictEqual(["file-size-sort", "file-size-sort"]);
});


test("InferSortClassesOnTH - DATES", () => {
expect(
createTestTable({
Expand Down Expand Up @@ -67,98 +65,97 @@ test("InferSortClassesOnTH - DATES", () => {
},
})
// two dates-dmy-sort as mdy is not an inferred class but explicit override.
).toStrictEqual(["dates-ymd-sort","dates-dmy-sort","dates-dmy-sort"]);
).toStrictEqual(["dates-ymd-sort", "dates-dmy-sort", "dates-dmy-sort"]);
});



test("InferSortClassesOnTH - RUNTIME", () => {
expect(
createTestTable({
col0: {
td: [
"2m 52s",
"1h 20m 10s",
"3s",
"11h 10m 10s",
"7s",
"11m 40s",
"36s",
"1h 10m 10s",
"9m 44s",
"1m 36s",
"41s",
],
},
col0: {
td: [
"2m 52s",
"1h 20m 10s",
"3s",
"11h 10m 10s",
"7s",
"11m 40s",
"36s",
"1h 10m 10s",
"9m 44s",
"1m 36s",
"41s",
],
},
})
).toStrictEqual(["runtime-sort"]);
});

test("InferSortClassesOnTH - NUMERIC", () => {
expect(
createTestTable({
// commas
col0: {
td: [
"20,000.89",
"30,000.32",
"1",
"0.111",
"21,000.92",
"19845",
"12000",
"-90",
"-10,000.39",
"-10,000.10",
],
},
// negative numbers
col1: { td: ["1.05", "-2.3", "-3", "1", "-6", "(1.4)", "14"] },
// decimals
col2: { td: ["0.1", "0.2", "0.3", "0.11", "0.13", "0.13", "0.14"] },
col3: {
td: [
"1.05",
"-2.3",
"-3",
"1",
"-6",
"",
"(0.5)",
"1a",
"b",
"(c)",
"{1}",
],
},
// TODO HANDLE CURRENCY $ / pounds, etc....
// commas
col0: {
td: [
"20,000.89",
"30,000.32",
"1",
"0.111",
"21,000.92",
"19845",
"12000",
"-90",
"-10,000.39",
"-10,000.10",
],
},
// negative numbers
col1: { td: ["1.05", "-2.3", "-3", "1", "-6", "(1.4)", "14"] },
// decimals
col2: { td: ["0.1", "0.2", "0.3", "0.11", "0.13", "0.13", "0.14"] },
col3: {
td: [
"1.05",
"-2.3",
"-3",
"1",
"-6",
"",
"(0.5)",
"1a",
"b",
"(c)",
"{1}",
],
},
// TODO HANDLE CURRENCY $ / pounds, etc....
col4: {
td: [
"-$4.01",
"-¥2.02",
"-$5.03",
"$4.64",
"-£29,675",
"-$5.21",
"-£50,854",
"£2,038,720",
"£283,838,720",
"-£481,177",
"$2.01",
"$2.11",
"$2.21",
"-£1,976,799",
"£2,265",
"-£420,252",
"-€2,409,060",
"-£755,905",
],
},
})
).toStrictEqual(["numeric-sort","numeric-sort","numeric-sort","numeric-sort"]);
).toStrictEqual([
"numeric-sort",
"numeric-sort",
"numeric-sort",
"numeric-sort",
"numeric-sort",
]);
});


// TODO no-class-infer
// test("InferSortClassesOnTH - no-class-infer", () => {
// expect(
// createTestTable(
// {
// col0: {
// td: [
// "2m 52s",
// "1h 20m 10s",
// "3s",
// "11h 10m 10s",
// "7s",
// "11m 40s",
// "36s",
// "1h 10m 10s",
// "9m 44s",
// "1m 36s",
// "41s",
// ],
// },
// },
// // props={ tableTags: "no-class-infer"},
// )
// ).toStrictEqual(["runtime-sort"]);
// });

0 comments on commit 8f38e5f

Please sign in to comment.