diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2025-09-30 13:34:10 +0200 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2025-09-30 13:37:25 +0200 |
| commit | e75d9e371269a4e46bffa6b3dd1fc7d040e82750 (patch) | |
| tree | c1f2a9aa8022a2710af5e5a577578855584540df /internal/mdedit/res | |
| parent | 0bb27576a37de4bf76dab35c73fa8790fcfa706a (diff) | |
| download | gofu-2025.1.tar.gz | |
add mdeditv2025.1
Diffstat (limited to 'internal/mdedit/res')
| -rw-r--r-- | internal/mdedit/res/app.js | 67 | ||||
| -rw-r--r-- | internal/mdedit/res/index.html | 18 | ||||
| -rw-r--r-- | internal/mdedit/res/style.css | 48 |
3 files changed, 133 insertions, 0 deletions
diff --git a/internal/mdedit/res/app.js b/internal/mdedit/res/app.js new file mode 100644 index 0000000..c934697 --- /dev/null +++ b/internal/mdedit/res/app.js @@ -0,0 +1,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); + } + }); + +})(); diff --git a/internal/mdedit/res/index.html b/internal/mdedit/res/index.html new file mode 100644 index 0000000..20aea13 --- /dev/null +++ b/internal/mdedit/res/index.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>mdedit</title> + <link rel="stylesheet" type="text/css" href="/res.css" /> +</head> +<body> + <nav> + <span id="title">mdedit</span>: <span id="status">Loading...</span> + </nav> + <textarea id="editor"></textarea> + <div id="preview"></div> +</body> +<script src="/res.js"></script> +</html> diff --git a/internal/mdedit/res/style.css b/internal/mdedit/res/style.css new file mode 100644 index 0000000..01cd0c2 --- /dev/null +++ b/internal/mdedit/res/style.css @@ -0,0 +1,48 @@ +:root { + height: 100vh; + overflow: none; +} + +body { + display: grid; + margin: 0; + padding: 0; + grid-template-rows: 2rem 1fr; + grid-template-columns: 1fr 1fr; + grid-template-areas: "nav nav" "editor preview"; + overflow: hidden; + height: 100vh; + font-family: system-ui, sans-serif; + + & > nav { grid-area: nav; } + & > textarea#editor { grid-area: editor; } + & > div#preview { grid-area: preview; } +} + +nav { + height: 2rem; + line-height: 2rem; + padding: 0 1rem; + background: #111; + color: white; + + & > span#title { font-weight: bold; } +} + +textarea#editor { + margin: 0; + border: none; + background: #333; + color: white; + + resize: none; + overflow-y: scroll; + height: 100%; +} + +div#preview { + padding: 0 1rem; + + overflow: scroll; + height: 100%; +} |
