Skip to content

Commit 8f38e5f

Browse files
Handle common currencies ($£€¥) with numeric-sort class. (#132)
* Handle common currencies and negatives. * Prettify files. * Add bitcoin and ethereum currency signs. * Update readme to say numeric-sort now supports currency
1 parent a510eb2 commit 8f38e5f

File tree

5 files changed

+173
-122
lines changed

5 files changed

+173
-122
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Examples on using table-sort-js with frontend frameworks such as [React.js](http
7272

7373
| <th> Inferred Classes. | Description |
7474
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
75-
| "numeric-sort" | Sorts numbers including decimals - Positive, Negative (in both minus and parenthesis representations) |
75+
| "numeric-sort" | Sorts numbers including decimals - Positive, Negative (in both minus and parenthesis representations). Supports for common currencies e.g ($£€¥) |
7676
| "dates-dmy-sort" | Sorts dates in dd/mm/yyyy format. e.g (18/10/1995). Can use "/" or "-" as separator. |
7777
| "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. |
7878
| "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. |

public/table-sort.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
6464
// Don't infer dates with delimiter "."; as could capture semantic version numbers.
6565
const dmyRegex = /^(\d\d?)[/-](\d\d?)[/-]((\d\d)?\d\d)/;
6666
const ymdRegex = /^(\d\d\d\d)[/-](\d\d?)[/-](\d\d?)/;
67-
// const numericRegex = /^(?:\(\d+(?:\.\d+)?\)|-?\d+(?:\.\d+)?)$/; doesn't handle commas
6867
const numericRegex =
69-
/^-?(?:\d{1,3}(?:[',]\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?(?:[',]\d{3})*?)$/;
68+
/^-?(?:[$£¥฿Ξξ¤¿\u20A1\uFFE0]\d{1,3}(?:[',]\d{3})*(?:\.\d+)?|\d+(?:\.\d+)?(?:[',]\d{3})*?)$/;
69+
70+
7071
const inferableClasses = {
7172
runtime: { regexp: runtimeRegex, class: "runtime-sort", count: 0 },
7273
filesize: { regexp: fileSizeRegex, class: "file-size-sort", count: 0 },
@@ -342,7 +343,7 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
342343
function parseNumberFromString(str) {
343344
let num;
344345
str = str.slice(0, str.indexOf("#"));
345-
if (str.match(/^\((\d+(?:\.\d+)?)\)$/)) {
346+
if (str.match(/^\(-?(\d+(?:\.\d+)?)\)$/)) {
346347
num = -1 * Number(str.slice(1, -1));
347348
} else {
348349
num = Number(str);
@@ -359,11 +360,10 @@ function tableSortJs(testingTableSortJS = false, domDocumentWindow = document) {
359360
}
360361

361362
function handleNumbers(str1, str2) {
362-
let num1, num2;
363-
str1 = str1.replaceAll(",", "");
364-
str2 = str2.replaceAll(",", "");
365-
num1 = parseNumberFromString(str1);
366-
num2 = parseNumberFromString(str2);
363+
const currencyAndComma = /[$£¥฿Ξξ¤¿\u20A1\uFFE0, ]/g
364+
str1 = str1.replace(currencyAndComma, "");
365+
str2 = str2.replace(currencyAndComma, "");
366+
const [num1, num2] = [parseNumberFromString(str1),parseNumberFromString(str2)];
367367

368368
if (!isNaN(num1) && !isNaN(num2)) {
369369
return num1 - num2;

test/table.test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,59 @@ test("Sort all combination of negative and positive integers and decimal numbers
617617
});
618618
});
619619

620+
test("numeric-sort - various currency", () => {
621+
expect(
622+
createTestTable(
623+
{
624+
col0: {
625+
td: [
626+
"-$4.01",
627+
"-¥2.02",
628+
"($5.03)",
629+
"$4.64",
630+
"-£29,675",
631+
"-$5.21",
632+
"-£50,854",
633+
"£2,038,720",
634+
"£283,838,720",
635+
"-£481,177",
636+
"$2.01",
637+
"$2.11",
638+
"฿2.21",
639+
"-£1,976,799",
640+
"£2,265",
641+
"(£420,252)",
642+
"-€2,409,060",
643+
"-£755,905",
644+
],
645+
},
646+
},
647+
{ classTags: "numeric-sort" }
648+
)
649+
).toStrictEqual({
650+
col0: [
651+
"-€2,409,060",
652+
"-£1,976,799",
653+
"-£755,905",
654+
"-£481,177",
655+
"(£420,252)",
656+
"-£50,854",
657+
"-£29,675",
658+
"-$5.21",
659+
"($5.03)",
660+
"-$4.01",
661+
"-¥2.02",
662+
"$2.01",
663+
"$2.11",
664+
"฿2.21",
665+
"$4.64",
666+
"£2,265",
667+
"£2,038,720",
668+
"£283,838,720",
669+
],
670+
});
671+
});
672+
620673
test("default behavior without cells-sort (tr's move when sorted)", () => {
621674
expect(
622675
createTestTable(

test/tagsInferenceTable.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ function createTestTable(
7676
tableSortJs(true, dom.window.document);
7777
// Make an array from table contents to test if sorted correctly.
7878
let table = dom.window.document.querySelector("table");
79-
const tableHeadWithInferredClassName = table
80-
.querySelectorAll("thead th")
81-
let inferedClassNamesOfTh = Array.from(tableHeadWithInferredClassName).map((e)=>e.getAttribute("class"))
79+
const tableHeadWithInferredClassName = table.querySelectorAll("thead th");
80+
let inferedClassNamesOfTh = Array.from(tableHeadWithInferredClassName).map(
81+
(e) => e.getAttribute("class")
82+
);
8283
return inferedClassNamesOfTh;
8384
}
8485

test/tagsInferenceTable.test.js

Lines changed: 107 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,39 @@
11
const createTestTable = require("./tagsInferenceTable");
22

3-
43
test("InferSortClassesOnTH - FILE SIZE", () => {
54
expect(
65
createTestTable({
7-
col0: {
8-
td: [
9-
"10MB",
10-
"10GB",
11-
"10TB",
12-
"10B",
13-
"10MiB",
14-
"10TiB",
15-
"10Kib",
16-
"10KB",
17-
"10GiB",
18-
],
19-
},
20-
// add in space and make some undercase
21-
col1: {
22-
td: [
23-
"10 mB",
24-
"10 GB",
25-
"10 Tb",
26-
"10 B",
27-
"10 mib",
28-
"10 tib",
29-
"10 kib",
30-
"10 kB",
31-
"10 giB",
32-
],
33-
},
6+
col0: {
7+
td: [
8+
"10MB",
9+
"10GB",
10+
"10TB",
11+
"10B",
12+
"10MiB",
13+
"10TiB",
14+
"10Kib",
15+
"10KB",
16+
"10GiB",
17+
],
18+
},
19+
// add in space and make some undercase
20+
col1: {
21+
td: [
22+
"10 mB",
23+
"10 GB",
24+
"10 Tb",
25+
"10 B",
26+
"10 mib",
27+
"10 tib",
28+
"10 kib",
29+
"10 kB",
30+
"10 giB",
31+
],
32+
},
3433
})
3534
).toStrictEqual(["file-size-sort", "file-size-sort"]);
3635
});
3736

38-
3937
test("InferSortClassesOnTH - DATES", () => {
4038
expect(
4139
createTestTable({
@@ -67,98 +65,97 @@ test("InferSortClassesOnTH - DATES", () => {
6765
},
6866
})
6967
// two dates-dmy-sort as mdy is not an inferred class but explicit override.
70-
).toStrictEqual(["dates-ymd-sort","dates-dmy-sort","dates-dmy-sort"]);
68+
).toStrictEqual(["dates-ymd-sort", "dates-dmy-sort", "dates-dmy-sort"]);
7169
});
7270

73-
74-
7571
test("InferSortClassesOnTH - RUNTIME", () => {
7672
expect(
7773
createTestTable({
78-
col0: {
79-
td: [
80-
"2m 52s",
81-
"1h 20m 10s",
82-
"3s",
83-
"11h 10m 10s",
84-
"7s",
85-
"11m 40s",
86-
"36s",
87-
"1h 10m 10s",
88-
"9m 44s",
89-
"1m 36s",
90-
"41s",
91-
],
92-
},
74+
col0: {
75+
td: [
76+
"2m 52s",
77+
"1h 20m 10s",
78+
"3s",
79+
"11h 10m 10s",
80+
"7s",
81+
"11m 40s",
82+
"36s",
83+
"1h 10m 10s",
84+
"9m 44s",
85+
"1m 36s",
86+
"41s",
87+
],
88+
},
9389
})
9490
).toStrictEqual(["runtime-sort"]);
9591
});
9692

9793
test("InferSortClassesOnTH - NUMERIC", () => {
9894
expect(
9995
createTestTable({
100-
// commas
101-
col0: {
102-
td: [
103-
"20,000.89",
104-
"30,000.32",
105-
"1",
106-
"0.111",
107-
"21,000.92",
108-
"19845",
109-
"12000",
110-
"-90",
111-
"-10,000.39",
112-
"-10,000.10",
113-
],
114-
},
115-
// negative numbers
116-
col1: { td: ["1.05", "-2.3", "-3", "1", "-6", "(1.4)", "14"] },
117-
// decimals
118-
col2: { td: ["0.1", "0.2", "0.3", "0.11", "0.13", "0.13", "0.14"] },
119-
col3: {
120-
td: [
121-
"1.05",
122-
"-2.3",
123-
"-3",
124-
"1",
125-
"-6",
126-
"",
127-
"(0.5)",
128-
"1a",
129-
"b",
130-
"(c)",
131-
"{1}",
132-
],
133-
},
134-
// TODO HANDLE CURRENCY $ / pounds, etc....
96+
// commas
97+
col0: {
98+
td: [
99+
"20,000.89",
100+
"30,000.32",
101+
"1",
102+
"0.111",
103+
"21,000.92",
104+
"19845",
105+
"12000",
106+
"-90",
107+
"-10,000.39",
108+
"-10,000.10",
109+
],
110+
},
111+
// negative numbers
112+
col1: { td: ["1.05", "-2.3", "-3", "1", "-6", "(1.4)", "14"] },
113+
// decimals
114+
col2: { td: ["0.1", "0.2", "0.3", "0.11", "0.13", "0.13", "0.14"] },
115+
col3: {
116+
td: [
117+
"1.05",
118+
"-2.3",
119+
"-3",
120+
"1",
121+
"-6",
122+
"",
123+
"(0.5)",
124+
"1a",
125+
"b",
126+
"(c)",
127+
"{1}",
128+
],
129+
},
130+
// TODO HANDLE CURRENCY $ / pounds, etc....
131+
col4: {
132+
td: [
133+
"-$4.01",
134+
"-¥2.02",
135+
"-$5.03",
136+
"$4.64",
137+
"-£29,675",
138+
"-$5.21",
139+
"-£50,854",
140+
"£2,038,720",
141+
"£283,838,720",
142+
"-£481,177",
143+
"$2.01",
144+
"$2.11",
145+
"$2.21",
146+
"-£1,976,799",
147+
"£2,265",
148+
"-£420,252",
149+
"-€2,409,060",
150+
"-£755,905",
151+
],
152+
},
135153
})
136-
).toStrictEqual(["numeric-sort","numeric-sort","numeric-sort","numeric-sort"]);
154+
).toStrictEqual([
155+
"numeric-sort",
156+
"numeric-sort",
157+
"numeric-sort",
158+
"numeric-sort",
159+
"numeric-sort",
160+
]);
137161
});
138-
139-
140-
// TODO no-class-infer
141-
// test("InferSortClassesOnTH - no-class-infer", () => {
142-
// expect(
143-
// createTestTable(
144-
// {
145-
// col0: {
146-
// td: [
147-
// "2m 52s",
148-
// "1h 20m 10s",
149-
// "3s",
150-
// "11h 10m 10s",
151-
// "7s",
152-
// "11m 40s",
153-
// "36s",
154-
// "1h 10m 10s",
155-
// "9m 44s",
156-
// "1m 36s",
157-
// "41s",
158-
// ],
159-
// },
160-
// },
161-
// // props={ tableTags: "no-class-infer"},
162-
// )
163-
// ).toStrictEqual(["runtime-sort"]);
164-
// });

0 commit comments

Comments
 (0)