generated from obsidianmd/obsidian-sample-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.ts
121 lines (108 loc) · 3.2 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
import { syntaxTree } from "@codemirror/language";
import { RangeSetBuilder } from "@codemirror/state";
import {
Decoration,
DecorationSet,
EditorView,
PluginValue,
ViewPlugin,
ViewUpdate,
WidgetType,
} from "@codemirror/view";
import { Plugin } from "obsidian";
class CheckboxWidget extends WidgetType {
constructor(readonly checked: boolean) {
super();
}
eq(other: CheckboxWidget) {
return other.checked == this.checked;
}
toDOM() {
const box = document.createElement("input");
box.classList.add("task-list-item-checkbox", "ec-task-list-toggle");
box.style.marginLeft = "6px";
box.type = "checkbox";
box.checked = this.checked;
return box;
}
ignoreEvent() {
return false;
}
}
class CheckBoxPlugin implements PluginValue {
decorations: DecorationSet;
constructor(view: EditorView) {
this.decorations = CheckBoxPlugin.checkboxes(view);
}
update(update: ViewUpdate) {
if (update.viewportChanged || update.selectionSet)
this.decorations = CheckBoxPlugin.checkboxes(update.view);
}
static checkboxes(view: EditorView) {
const widgets = new RangeSetBuilder<Decoration>();
for (const { from, to } of view.visibleRanges) {
syntaxTree(view.state).iterate({
from,
to,
enter: (node) => {
const maybe_list = view.state.doc.sliceString(
node.from - 3,
node.from
);
if (
node.type.name.startsWith("list") &&
/\[.\]/.test(maybe_list)
) {
const cur_pos = view.state.selection.main.head;
if (!(node.from - 5 <= cur_pos && cur_pos <= node.from)) {
widgets.add(
node.from - 4,
node.from,
Decoration.replace({})
);
}
widgets.add(
node.to,
node.to,
Decoration.widget({
widget: new CheckboxWidget(maybe_list[1] == "x"),
side: 1,
})
);
}
},
});
}
return widgets.finish();
}
}
const toggleTaskHandler = {
mousedown: (e: Event, view: EditorView) => {
const target = e.target as HTMLInputElement;
if (
target.nodeName == "INPUT" &&
target.classList.contains("ec-task-list-toggle")
) {
e.preventDefault();
const line = view.state.doc.lineAt(view.posAtDOM(target));
const start = line.from + line.text.indexOf("- [");
view.dispatch({
changes: {
from: start + 3,
to: start + 4,
insert: target.checked ? " " : "x",
},
});
}
},
};
export default class EndCheckerPlugin extends Plugin {
async onload() {
this.registerEditorExtension([
ViewPlugin.fromClass(CheckBoxPlugin, {
decorations: (v) => v.decorations,
eventHandlers: toggleTaskHandler,
}),
]);
}
}