1import QuestionRender from "#src/q+a/tags/question.marko";
2import type { ScriptPayload } from "#src/q+a/views/editor.marko";
3
4declare const payload: ScriptPayload;
5const date = new Date(payload.date);
6
7const main = document.getElementById("edit-grid")! as HTMLDivElement;
8const preview = document.getElementById("preview")! as HTMLDivElement;
9const editor = document.getElementById("editor") as HTMLTextAreaElement;
10
11async function updatePreview(text: string) {
12 preview.innerHTML = await QuestionRender.render({
13 question: {
14 id: payload.id,
15 qmid: payload.qmid,
16 text: text,
17 type: payload.type,
18 date,
19 },
20 editor: true,
21 });
22}
23updatePreview(payload.text);
24
25editor.value = payload.text;
26editor.addEventListener("input", () => {
27 updatePreview(editor.value);
28});
29editor.focus();
30
31(globalThis as any).onCommitQuestion = wrapAction(async () => {
32 const text = editor.value;
33 const res = await fetch(`/admin/q+a/${payload.id}`, {
34 method: "PATCH",
35 headers: {
36 Accept: "application/json",
37 "Content-Type": "application/json",
38 },
39 body: JSON.stringify({
40 text,
41 type: payload.type,
42 }),
43 });
44 if (!res.ok) {
45 throw new Error("Failed to update question, status: " + res.status);
46 }
47 if (location.search.includes("return=inbox")) {
48 location.href = "/admin/q+a/inbox";
49 } else {
50 location.href = "/q+a#q" + payload.id;
51 }
52});
53(globalThis as any).onDelete = wrapAction(async () => {
54 if (confirm("Are you sure you want to delete this question?")) {
55 const res = await fetch(`/admin/q+a/${payload.id}`, {
56 method: "DELETE",
57 headers: {
58 Accept: "application/json",
59 },
60 });
61 if (!res.ok) {
62 throw new Error("Failed to delete question, status: " + res.status);
63 }
64 location.href = document.referrer || "/admin/q+a";
65 }
66});
67(globalThis as any).onTypeChange = () => {
68 payload.type = parseInt(
69 (document.getElementById("type") as HTMLSelectElement).value,
70 );
71 updatePreview(view.state.doc.toString());
72};
73
74function wrapAction(cb: () => Promise<void>) {
75 return async () => {
76 main.style.opacity = "0.5";
77 main.style.pointerEvents = "none";
78 const inputs = main.querySelectorAll(
79 "button,select,input",
80 ) as NodeListOf<HTMLButtonElement>;
81 inputs.forEach((b) => {
82 b.disabled = true;
83 });
84 try {
85 await cb();
86 } catch (e: any) {
87 main.style.opacity = "1";
88 main.style.pointerEvents = "auto";
89 inputs.forEach((b) => {
90 b.disabled = false;
91 });
92 alert(e.message);
93 }
94 };
95}