-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.ts
156 lines (131 loc) · 4.68 KB
/
main.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import { Plugin, TFile, Vault } from 'obsidian';
import { IFile, VaultFileService } from 'src/fileService';
import { DEFAULT_SETTINGS, ExtendedTaskListsSettingTab, ExtendedTaskListsSettings } from 'src/settings';
import TodoService, { Todo } from 'src/todoService';
export default class ExtendedTaskListsPlugin extends Plugin {
settings: ExtendedTaskListsSettings
async onload() {
await this.loadSettings()
// ignore create events on vault load
this.app.workspace.onLayoutReady(() => {
this.registerEvent(this.app.vault.on("create", this.updateTodoFile))
})
// TODO(joeriddles): only re-run updateTodo for changed file(s)
this.registerEvent(this.app.vault.on("delete", this.updateTodoFile))
this.registerEvent(this.app.vault.on("rename", this.updateTodoFile))
this.registerEvent(this.app.vault.on("modify", async (file) => {
if (file.name !== this.settings.todoFilename || !(file instanceof TFile)) {
await this.updateTodoFile();
return
}
const hasChanges = await this.onTodoFileUpdated(file);
if (hasChanges) {
await this.updateTodoFile();
}
}))
this.addCommand({
id: 'update-todo',
name: 'Update TODO',
callback: this.updateTodoFile,
})
this.addSettingTab(new ExtendedTaskListsSettingTab(this.app, this))
this.registerMarkdownPostProcessor((element, context) => {
const taskItems = element.findAll(".task-list-item")
for (const taskItem of taskItems) {
const char = taskItem.dataset.task
const checkbox = taskItem.find("input[type='checkbox']") as HTMLInputElement
switch (char) {
case ".":
checkbox.indeterminate = true
registerIndeterminateClick(checkbox)
break
case "~":
checkbox.classList.add("wont-do")
taskItem.classList.add("wont-do")
registerWontDoClick(checkbox, taskItem)
break
}
}
})
const registerIndeterminateClick = (checkbox: HTMLInputElement) => {
let handled = false
this.registerDomEvent(checkbox, 'click', (evt: MouseEvent) => {
if (handled) {
return
}
handled = true
checkbox.indeterminate = false
checkbox.checked = true
evt.stopPropagation()
})
}
const registerWontDoClick = (checkbox: HTMLInputElement, taskItem: HTMLElement) => {
let handled = false
this.registerDomEvent(checkbox, 'click', (evt: MouseEvent) => {
if (handled) {
return
}
handled = true
checkbox.checked = true
checkbox.classList.remove("wont-do")
taskItem.classList.remove("wont-do")
evt.stopPropagation()
})
}
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData())
}
async saveSettings() {
await this.saveData(this.settings)
}
updateTodoFile = async () => {
const vault = this.app.vault
const fileService = new VaultFileService(vault)
const service = new TodoService(fileService, this.settings)
const todoFiles = await service.findTodosFiles()
const todos: Todo[] = todoFiles
.map(todoFile => {
const todos = service.parseTodos(todoFile.contents)
todos.forEach(todo => todo.file = todoFile.file)
return todos
})
.reduce((prev, cur) => prev.concat(cur), [])
const todoFile = await this.getOrCreateTodoFile(vault);
await service.saveTodos(todoFile as IFile, todos)
}
onTodoFileUpdated = async (todoFile: TFile): Promise<boolean> => {
const vault = this.app.vault
const fileService = new VaultFileService(vault)
const contents = await fileService.readFile(todoFile as IFile)
const service = new TodoService(fileService, this.settings)
const todosByFilePath = service.parseTodoFile(contents)
const hasUpdates = false
todosByFilePath.forEach(async (todos, filepath) => {
const includedTaskTypes = service.getIncludedTaskTypes()
const updatedTodos = todos.filter(todo => !includedTaskTypes.has(todo.task))
if (updatedTodos.length === 0) return
const file = await fileService.getFileByPath(filepath)
if (file == null) return
const fileContent = await fileService.readFile(file)
const newFileContent = await service.updateTodos(fileContent, updatedTodos)
await fileService.updateFile(file, newFileContent)
})
return hasUpdates
}
getOrCreateTodoFile = async (vault: Vault): Promise<TFile> => {
let todoFile: TFile
try {
todoFile = await vault.create(this.settings.todoFilename, "")
} catch (e) {
const todoFileOrNull = vault.getAbstractFileByPath(this.settings.todoFilename)
if (todoFileOrNull == null) {
throw new Error(`Could not get or create the TODO file: ${this.settings.todoFilename}`)
} else if (!(todoFileOrNull instanceof TFile)) {
throw new Error(`The retrieved TODO file is a folder: ${this.settings.todoFilename}`)
}
todoFile = todoFileOrNull
}
return todoFile
}
}