#27 - support for true alphabetical order

- added new token 'true a-z'
- unit tests coverage of the extended logic
- added example in README.md
This commit is contained in:
SebastianMC 2022-11-10 00:10:16 +01:00
parent 4bd3eaadfd
commit 742bdf1b80
5 changed files with 81 additions and 1 deletions

View File

@ -308,7 +308,7 @@ sorting-spec: |
the line `... part \d+` says: group all notes and folders with name ending with 'part' followed by a number. Then order
them by the number. And for clarity the subsequent (indented) line is added ` < a-z` which sets the order to
alphanumerical ascending.
alphabetical ascending.
The effect is:
@ -411,6 +411,35 @@ sorting-spec: |
---
```
## Alphabetical, Natural and True Alphabetical sorting orders
The 'A-Z' sorting (visible in Obsidian UI of file explorer) at some point before the 1.0.0 release of Obsidian actually became the so-called 'natural' sort order.
For explanation of the term go to [Natural sort order](https://en.wikipedia.org/wiki/Natural_sort_order) on Wikipedia.
The plugin follows the convention and the sorting specified by `< a-z` or `> a-z` triggers the _'natural sort order'_.
To allow the true alphabetical sort order, as suggested by the ticket [27: Not alphanumeric, but natural sort order?](https://github.com/SebastianMC/obsidian-custom-sort/issues/27)
a distinct syntax was introduced: `< true a-z` and `> true a-z`
What is the difference?
Using the example from the mentioned ticket: the items '0x01FF', '0x02FF' and '0x0200' sorted in _natural order_ go as:
- 0x01FF -> the number 01 in the text is recognized
- 0x02FF -> the number 02 in the text is recognized
- 0x0200 -> the number 0200 in the text is recognized and it causes the third position of the item, because 0200 > 02
The same items when sorted in _true alphabetical_ order go as:
- 0x01FF
- 0x0200
- 0x02FF -> the character 'F' following '2' goes after the character '0', that's why 0x02FF follows the 0x0200
You can use the order `< true a-z` or `> true a-z` to trigger the true alphabetical sorting, like in the ticket:
```yaml
sorting-spec: |
target-folder: MaDo/...
> true a-z
target-folder: MaDo/Sandbox/SortingBug
< true a-z
```
## Location of sorting specification YAML entry
You can keep the custom sorting specifications in any of the following locations (or in all of them):

View File

@ -9,7 +9,9 @@ export enum CustomSortGroupType {
export enum CustomSortOrder {
alphabetical = 1, // = 1 to allow: if (customSortOrder) { ...
trueAlphabetical,
alphabeticalReverse,
trueAlphabeticalReverse,
byModifiedTime, // New to old
byModifiedTimeAdvanced,
byModifiedTimeReverse, // Old to new

View File

@ -8,6 +8,12 @@ let Collator = new Intl.Collator(undefined, {
numeric: true,
}).compare;
let CollatorTrueAlphabetical = new Intl.Collator(undefined, {
usage: "sort",
sensitivity: "base",
numeric: false,
}).compare;
export interface FolderItemForSorting {
path: string
groupIdx?: number // the index itself represents order for groups
@ -24,7 +30,9 @@ type SorterFn = (a: FolderItemForSorting, b: FolderItemForSorting) => number
let Sorters: { [key in CustomSortOrder]: SorterFn } = {
[CustomSortOrder.alphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(a.sortString, b.sortString),
[CustomSortOrder.trueAlphabetical]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabetical(a.sortString, b.sortString),
[CustomSortOrder.alphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => Collator(b.sortString, a.sortString),
[CustomSortOrder.trueAlphabeticalReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => CollatorTrueAlphabetical(b.sortString, a.sortString),
[CustomSortOrder.byModifiedTime]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (a.mtime - b.mtime),
[CustomSortOrder.byModifiedTimeAdvanced]: (a: FolderItemForSorting, b: FolderItemForSorting) => a.mtime - b.mtime,
[CustomSortOrder.byModifiedTimeReverse]: (a: FolderItemForSorting, b: FolderItemForSorting) => (a.isFolder && b.isFolder) ? Collator(a.sortString, b.sortString) : (b.mtime - a.mtime),

View File

@ -436,6 +436,46 @@ describe('SortingSpecProcessor', () => {
})
})
const txtInputTrueAlphabeticalSortAttr: string = `
target-folder: AAA
< true a-z
target-folder: BBB
> true a-z
`
const expectedSortSpecForTrueAlphabeticalSorting: { [key: string]: CustomSortSpec } = {
"AAA": {
defaultOrder: CustomSortOrder.trueAlphabetical,
groups: [{
order: CustomSortOrder.trueAlphabetical,
type: CustomSortGroupType.Outsiders
}],
outsidersGroupIdx: 0,
targetFoldersPaths: ['AAA']
},
"BBB": {
defaultOrder: CustomSortOrder.trueAlphabeticalReverse,
groups: [{
order: CustomSortOrder.trueAlphabeticalReverse,
type: CustomSortGroupType.Outsiders
}],
outsidersGroupIdx: 0,
targetFoldersPaths: ['BBB']
}
}
describe('SortingSpecProcessor', () => {
let processor: SortingSpecProcessor;
beforeEach(() => {
processor = new SortingSpecProcessor();
});
it('should recognize the true alphabetical (and reverse) sorting attribute for a folder', () => {
const inputTxtArr: Array<string> = txtInputTrueAlphabeticalSortAttr.split('\n')
const result = processor.parseSortSpecFromText(inputTxtArr, 'mock-folder', 'custom-name-note.md')
expect(result?.sortSpecByPath).toEqual(expectedSortSpecForTrueAlphabeticalSorting)
})
})
const txtInputSimplistic1: string = `
target-folder: /*
/:files

View File

@ -84,6 +84,7 @@ interface CustomSortOrderAscDescPair {
// remember about .toLowerCase() before comparison!
const OrderLiterals: { [key: string]: CustomSortOrderAscDescPair } = {
'a-z': {asc: CustomSortOrder.alphabetical, desc: CustomSortOrder.alphabeticalReverse},
'true a-z': {asc: CustomSortOrder.trueAlphabetical, desc: CustomSortOrder.trueAlphabeticalReverse},
'created': {asc: CustomSortOrder.byCreatedTime, desc: CustomSortOrder.byCreatedTimeReverse},
'modified': {asc: CustomSortOrder.byModifiedTime, desc: CustomSortOrder.byModifiedTimeReverse},
'advanced modified': {asc: CustomSortOrder.byModifiedTimeAdvanced, desc: CustomSortOrder.byModifiedTimeReverseAdvanced},