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
|
(() => {
const $ = selector => document.querySelector(selector);
const handleResponse = (promise, action) => {
const error = promise.then(response => {
if (!response.ok) {
throw new Error(`HTTP error, status = ${response.status} from ${response.url}`);
}
const title = response.headers.get("X-Mdedit-Path");
if (title !== null && title !== "") {
window.document.title = "mdedit: " + title;
$("span#title").innerText = title;
}
return response.text();
}).then(body => {
action(body);
return null;
}).catch((error) => {
return error;
}).then((error) => {
if (error != null) {
console.log(error);
$("span#status").innerText = `Error: ${error.message}`;
}
});
};
// handler for receiving a rendered HTML from the server
const receiveHTML = body => {
$("div#preview").innerHTML = body;
$("span#status").innerText = "Saved";
};
// whenever the <textedit> changes, wait 3 seconds and then save all changes
let timeoutID = null;
const onTextChange = event => {
if (timeoutID !== null) {
window.clearTimeout(timeoutID);
}
timeoutID = window.setTimeout(uploadMarkdown, 1000);
$("span#status").innerText = "Changed";
};
const uploadMarkdown = () => {
window.clearTimeout(timeoutID);
timeoutID = null;
$("span#status").innerText = "Saving...";
const opts = {
method: "PUT",
body: $("textarea#editor").value,
};
handleResponse(fetch("/data.md", opts), receiveHTML);
};
// load Markdown and rendered HTML on startup
handleResponse(fetch("/data.md"), body => {
const editor = $("textarea#editor");
$("textarea#editor").value = body;
handleResponse(fetch("/data.html"), receiveHTML);
// avoid a useless upload on startup by attaching this only after the initial load is done
for (const eventType of ["change", "input", "textInput"]) {
editor.addEventListener(eventType, onTextChange);
}
});
})();
|