generated from obsidianmd/obsidian-sample-plugin
-
-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3110 from obsidian-tasks-group/add-random-sort
feat: Add random sorting, with 'sort by random'
- Loading branch information
Showing
7 changed files
with
161 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import type { Comparator } from '../Sort/Sorter'; | ||
import type { Task } from '../../Task/Task'; | ||
import { FilterInstructionsBasedField } from './FilterInstructionsBasedField'; | ||
|
||
/** | ||
* Sort tasks in a stable, random order. | ||
* | ||
* The sort order changes each day. | ||
*/ | ||
export class RandomField extends FilterInstructionsBasedField { | ||
public fieldName(): string { | ||
return 'random'; | ||
} | ||
|
||
// ----------------------------------------------------------------------------------------------------------------- | ||
// Sorting | ||
// ----------------------------------------------------------------------------------------------------------------- | ||
|
||
supportsSorting(): boolean { | ||
return true; | ||
} | ||
|
||
public comparator(): Comparator { | ||
return (a: Task, b: Task) => { | ||
return this.sortKey(a) - this.sortKey(b); | ||
}; | ||
} | ||
|
||
public sortKey(task: Task): number { | ||
// Credit: | ||
// - @qelo https://github.com/obsidian-tasks-group/obsidian-tasks/discussions/330#discussioncomment-8902878 | ||
// - Based on TinySimpleHash in https://stackoverflow.com/a/52171480/104370 | ||
const tinySimpleHash = (s: string): number => { | ||
let i = 0; // Index for iterating over the string | ||
let h = 9; // Initial hash value | ||
|
||
while (i < s.length) { | ||
h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); | ||
} | ||
|
||
return h ^ (h >>> 9); | ||
}; | ||
|
||
const currentDate = window.moment().format('Y-MM-DD'); | ||
return tinySimpleHash(currentDate + ' ' + task.description); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/** | ||
* @jest-environment jsdom | ||
*/ | ||
import moment from 'moment'; | ||
|
||
import { RandomField } from '../../../src/Query/Filter/RandomField'; | ||
import { fromLine } from '../../TestingTools/TestHelpers'; | ||
import { expectTaskComparesEqual } from '../../CustomMatchers/CustomMatchersForSorting'; | ||
import { TaskBuilder } from '../../TestingTools/TaskBuilder'; | ||
|
||
window.moment = moment; | ||
|
||
const field = new RandomField(); | ||
|
||
beforeAll(() => { | ||
jest.useFakeTimers(); | ||
jest.setSystemTime(new Date('2024-01-23')); | ||
}); | ||
|
||
afterAll(() => { | ||
jest.useRealTimers(); | ||
}); | ||
|
||
describe('filtering by random', () => { | ||
it('should be named random', () => { | ||
expect(field.fieldName()).toEqual('random'); | ||
}); | ||
}); | ||
|
||
describe('sorting by random', () => { | ||
it('should support sorting', () => { | ||
expect(field.supportsSorting()).toEqual(true); | ||
}); | ||
|
||
it('should sort identical tasks the same', () => { | ||
const sorter = field.createNormalSorter(); | ||
const task1 = fromLine({ line: '- [ ] Some description' }); | ||
|
||
expectTaskComparesEqual(sorter, task1, task1); | ||
}); | ||
|
||
it('sort key should ignore task properties except description', () => { | ||
const fullyPopulatedTask = TaskBuilder.createFullyPopulatedTask(); | ||
const taskWithSameDescription = new TaskBuilder().description(fullyPopulatedTask.description).build(); | ||
expect(field.sortKey(fullyPopulatedTask)).toEqual(field.sortKey(taskWithSameDescription)); | ||
}); | ||
|
||
it('sort key should not change, at different times', () => { | ||
const task1 = fromLine({ line: '- [ ] My sort key should be same, regardless of time' }); | ||
|
||
jest.setSystemTime(new Date('2024-10-19 10:42')); | ||
const sortKeyAtTime1 = field.sortKey(task1); | ||
|
||
jest.setSystemTime(new Date('2024-10-19 21:05')); | ||
const sortKeyAtTime2 = field.sortKey(task1); | ||
|
||
expect(sortKeyAtTime1).toEqual(sortKeyAtTime2); | ||
}); | ||
|
||
it('sort key should change on different dates', () => { | ||
const task1 = fromLine({ line: '- [ ] My sort key should differ on different dates' }); | ||
|
||
jest.setSystemTime(new Date('2024-01-23')); | ||
const sortKeyOnDay1 = field.sortKey(task1); | ||
|
||
jest.setSystemTime(new Date('2024-01-24')); | ||
const sortKeyOnDay2 = field.sortKey(task1); | ||
|
||
expect(sortKeyOnDay1).not.toEqual(sortKeyOnDay2); | ||
}); | ||
}); | ||
|
||
describe('grouping by random', () => { | ||
it('should not support grouping', () => { | ||
expect(field.supportsGrouping()).toEqual(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters