document.querySelectorAll("textarea[data-md]").forEach(function (area) { var bar = document.createElement("div"); bar.className = "mdbar"; var write = button("Write"), view = button("Preview"), attach = button("Attach image"); var pick = document.createElement("input"); pick.type = "file"; pick.accept = "image/png,image/jpeg,image/gif,image/webp"; pick.multiple = true; pick.hidden = true; var shown = document.createElement("div"); shown.className = "readme mdpreview"; shown.hidden = true; write.classList.add("on"); bar.append(write, view, attach, pick); area.before(bar); area.after(shown); function button(label) { var b = document.createElement("button"); b.type = "button"; b.textContent = label; return b; } function mode(preview) { write.classList.toggle("on", !preview); view.classList.toggle("on", preview); area.hidden = preview; shown.hidden = !preview; } write.onclick = function () { mode(false); area.focus(); }; if (area.form) area.form.addEventListener("submit", function () { mode(false); }); view.onclick = function () { shown.textContent = "Loading…"; mode(true); fetch("/preview", { method: "POST", body: new URLSearchParams({ body: area.value }) }) .then(function (r) { return r.text(); }) .then(function (html) { shown.innerHTML = area.value.trim() ? html : "
Nothing to preview.
"; }); }; attach.onclick = function () { pick.click(); }; pick.onchange = function () { send(pick.files); pick.value = ""; }; area.addEventListener("paste", function (e) { var files = e.clipboardData && e.clipboardData.files; if (files && files.length) { e.preventDefault(); send(files); } }); area.addEventListener("dragover", function (e) { e.preventDefault(); }); area.addEventListener("drop", function (e) { if (e.dataTransfer.files.length) { e.preventDefault(); send(e.dataTransfer.files); } }); function insert(text) { var at = area.selectionStart, end = area.selectionEnd; area.value = area.value.slice(0, at) + text + area.value.slice(end); area.selectionStart = area.selectionEnd = at + text.length; } function send(files) { Array.prototype.forEach.call(files, function (file) { var name = file.name.replace(/[\[\]()]/g, "") || "image"; var marker = "![Uploading " + name + "…]()"; insert(marker + "\n"); fetch("/attachments", { method: "POST", body: file }) .then(function (r) { return r.ok ? r.json() : r.text().then(function (t) { throw new Error(t.trim()); }); }) .then(function (j) { area.value = area.value.replace(marker, ""); }) .catch(function (err) { area.value = area.value.replace(marker + "\n", ""); alert(err.message); }); }); } }); document.addEventListener("click", function (e) { document.querySelectorAll("details.bell[open]").forEach(function (d) { if (!d.contains(e.target)) d.open = false; }); });