-
-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathfuzzy_date.ts
79 lines (63 loc) · 2.61 KB
/
fuzzy_date.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import * as chrono from 'chrono-node'
import {afterClosingBrackets} from '../common/brackets'
import {RoamDate} from '../roam/date'
import {RoamNode, Selection} from '../roam/roam-node'
import {Roam} from '../roam/roam'
import {NodeWithDate} from '../roam/date/withDate'
import {Feature, Settings} from '../settings'
import {Browser} from '../common/browser'
export const config: Feature = {
id: 'fuzzy-date',
name: 'Fuzzy Date',
enabledByDefault: true,
settings: [{type: 'string', id: 'guard', initValue: ';', label: 'Guard symbol'}],
}
const checkSettingsAndToggleFuzzyDate = () => {
Settings.isActive(config.id).then(active => (active ? registerEventListener() : removeEventListener()))
}
checkSettingsAndToggleFuzzyDate()
Browser.addMessageListener(async message => {
if (message === 'settings-updated') {
checkSettingsAndToggleFuzzyDate()
}
})
const getCursor = (node: RoamNode, newText: string, searchStart: number = 0) =>
node.text === newText ? node.selection.start : afterClosingBrackets(newText, searchStart)
export function replaceFuzzyDate(guard: string) {
const dateContainerExpr = new RegExp(`${guard}\(\.\{3,\}\?\)${guard}`, 'gm')
Roam.applyToCurrent(node => {
const match = node.text.match(dateContainerExpr)
if (!match) return node
const dateStr = match[0]
const date = chrono.parseDate(dateStr, new Date(), {
forwardDate: true,
})
if (!date) return node
const replaceMode = dateStr.startsWith(';:')
const replaceWith = replaceMode ? '' : RoamDate.formatPage(date)
const newText = node.text.replace(dateContainerExpr, replaceWith)
const cursor = getCursor(node, newText, replaceMode ? 0 : node.selection.start)
const newNode = new NodeWithDate(newText, new Selection(cursor, cursor))
return replaceMode ? newNode.withDate(date) : newNode
})
}
/**
* We use `keypress`, since `keyup` is sometimes firing for individual keys instead of the pressed key
* when the guard character is requiring a multi-key stroke.
*
* `setTimeout` is used to put the callback to the end of the event queue,
* since the input is not yet changed when keypress is firing.
*/
const registerEventListener = () => {
document.addEventListener('keypress', keypressListener)
}
const removeEventListener = () => {
document.removeEventListener('keypress', keypressListener)
}
const keypressListener = (ev: KeyboardEvent) => {
Settings.get(config.id, 'guard').then((value: string) => {
if (ev.key === value) {
setTimeout(() => replaceFuzzyDate(value), 0)
}
})
}