From 24b3d079d2180af63a970a8fac4bd4b21f80037c Mon Sep 17 00:00:00 2001 From: Alexandru Dinu Date: Tue, 10 Jan 2023 23:42:04 +0200 Subject: [PATCH] (#33) Introduce sorting by ISO dates. --- CHANGELOG.md | 6 ++++++ VERSION | 1 + package.json | 6 +++--- src/sortable.ts | 46 ++++++++++++++++++++++++++++++++-------------- 4 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 VERSION diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d15f2d..48016c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ All notable changes to this project will be documented in this file. See also the [releases](https://github.com/alexandru-dinu/obsidian-sortable/releases) page. +## [0.3.0] - 2023-01-10 +### Added +- Introduce sorting by ISO dates ([regex](https://regex101.com/r/RfMAcx/1)). + - Mandatory format is `YYYY-MM-DD`, time is optional. + ## [0.2.6] - 2022-08-06 ### Fixed - Don't show up-down arrows for the default table state; only show up / down arrows for ascending / descending sorting. @@ -39,6 +44,7 @@ See also the [releases](https://github.com/alexandru-dinu/obsidian-sortable/rele ### Added - Sort tables in ascending & descending order. +[0.3.0]: https://github.com/alexandru-dinu/obsidian-sortable/compare/0.2.6...0.3.0 [0.2.6]: https://github.com/alexandru-dinu/obsidian-sortable/compare/0.2.5...0.2.6 [0.2.5]: https://github.com/alexandru-dinu/obsidian-sortable/compare/0.2.4...0.2.5 [0.2.4]: https://github.com/alexandru-dinu/obsidian-sortable/compare/0.2.3...0.2.4 diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..0d91a54 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.3.0 diff --git a/package.json b/package.json index 3d0720e..c522768 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "obsidian-sample-plugin", - "version": "0.12.0", - "description": "This is a sample plugin for Obsidian (https://obsidian.md)", + "name": "obsidian-sortable", + "version": "0.3.0", + "description": "Table sorting plugin", "main": "main.js", "scripts": { "dev": "rollup --config rollup.config.js -w", diff --git a/src/sortable.ts b/src/sortable.ts index 8c5aba5..205d18a 100644 --- a/src/sortable.ts +++ b/src/sortable.ts @@ -1,3 +1,12 @@ +// allows time to be optional +const ISO_DATE_REGEX = /^(\d{4}-\d{2}-\d{2})(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/; + +enum CellTypes { + TEXT, + NUMBER, + ISO_DATE, +} + enum SortOrder { DEFAULT, ASCENDING, @@ -21,8 +30,7 @@ export type TTableStates = WeakMap; function shouldSort(htmlEl: HTMLElement): boolean { // dataview table: parent must be a "dataview" HTMLTableElement const p = htmlEl.matchParent(".dataview"); - if (p instanceof HTMLTableElement) - return true; + if (p instanceof HTMLTableElement) return true; // reading mode, i.e. non-editing return null !== htmlEl.matchParent(".markdown-reading-view"); @@ -119,28 +127,38 @@ function compareRows( order: SortOrder, collator: Intl.Collator ) { - let valueA = valueFromCell(a.cells[index]); - let valueB = valueFromCell(b.cells[index]); + let [valueA, typeA] = valueFromCell(a.cells[index]); + let [valueB, typeB] = valueFromCell(b.cells[index]); if (order === SortOrder.DESCENDING) { [valueA, valueB] = [valueB, valueA]; } - if (typeof valueA === "number" && typeof valueA === "number") { - return valueA < valueB ? -1 : 1; + if (typeA !== typeB) { + return collator.compare(valueA.toString(), valueB.toString()); } - return collator.compare(valueA.toString(), valueB.toString()); -} - -function tryParseFloat(x: string): string | number { - const y = parseFloat(x); - return isNaN(y) ? x : y; + switch (typeA) { + case CellTypes.NUMBER: + case CellTypes.ISO_DATE: + return valueA === valueB ? 0 : valueA < valueB ? -1 : 1; + case CellTypes.TEXT: + return collator.compare(valueA.toString(), valueB.toString()); + } } -function valueFromCell(element: HTMLTableCellElement) { +function valueFromCell(element: HTMLTableCellElement): [any, CellTypes] { // TODO: extend to other data-types. - return tryParseFloat(element.textContent); + const text = element.textContent; + + if (ISO_DATE_REGEX.test(text)) { + return [new Date(text), CellTypes.ISO_DATE]; + } + const value = parseFloat(text); + if (!isNaN(value)) { + return [value, CellTypes.NUMBER]; + } + return [text, CellTypes.TEXT]; } function emptyTable(tableBody: HTMLTableSectionElement, rows: Array) {