first commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { api } from "./api.js?v=0.6.0";
|
||||
import { copyText } from "./clipboard.js?v=0.6.0";
|
||||
import { applyFormat } from "./editor-format.js?v=0.6.0";
|
||||
import { renderMarkdown } from "./markdown.js?v=0.6.0";
|
||||
import { getPassword, setPassword } from "./session.js?v=0.6.0";
|
||||
import { NoteSocket } from "./socket.js?v=0.6.0";
|
||||
import { currentShareUrl, readEditorState, writeEditorState } from "./url-state.js?v=0.6.0";
|
||||
|
||||
const parts = location.pathname.split("/").filter(Boolean);
|
||||
const workspaceSlug = parts[1], noteSlug = parts[3];
|
||||
const editor = document.querySelector("#editor"), preview = document.querySelector("#preview"), editorWorkspace = document.querySelector("#editor-workspace");
|
||||
const modeToggle = document.querySelector("#mode-toggle"), passwordDialog = document.querySelector("#password-dialog");
|
||||
let password = getPassword(workspaceSlug), info, socket, saveTimer, applyingRemote = false, uiState = readEditorState();
|
||||
|
||||
function toast(text) { const el = document.querySelector("#toast"); el.textContent = text; el.classList.add("visible"); setTimeout(() => el.classList.remove("visible"), 1600); }
|
||||
function setStatus(kind, text) { document.querySelector("#status-dot").className = `status__dot${kind ? ` is-${kind}` : ""}`; document.querySelector("#status-text").textContent = text; }
|
||||
function updateAddressLabel() { document.querySelector("#note-url").textContent = `${location.pathname}${location.search}`; }
|
||||
function render() {
|
||||
if (uiState.mode === "markdown") { preview.classList.remove("preview--raw"); preview.innerHTML = renderMarkdown(editor.value); document.querySelector("#preview-label").textContent = "Podgląd Markdown"; }
|
||||
else { preview.classList.add("preview--raw"); preview.textContent = editor.value; document.querySelector("#preview-label").textContent = "Tekst źródłowy"; }
|
||||
document.querySelector("#characters").textContent = `${editor.value.length} znaków`;
|
||||
const words = editor.value.trim() ? editor.value.trim().split(/\s+/).length : 0; document.querySelector("#words").textContent = `${words} słów`;
|
||||
}
|
||||
function applyUi({ write = false, replace = false } = {}) {
|
||||
editorWorkspace.className = `workspace view-${uiState.view}`;
|
||||
document.querySelectorAll("[data-view]").forEach(button => { const active = button.dataset.view === uiState.view; button.classList.toggle("active", active); button.setAttribute("aria-pressed", String(active)); });
|
||||
const markdown = uiState.mode === "markdown"; modeToggle.classList.toggle("active", markdown); modeToggle.setAttribute("aria-pressed", String(markdown)); modeToggle.textContent = markdown ? "Markdown" : "Tekst"; modeToggle.title = markdown ? "Kliknij, aby pokazać tekst bez interpretacji" : "Kliknij, aby interpretować Markdown";
|
||||
render(); if (write) writeEditorState(uiState, { replace }); updateAddressLabel();
|
||||
}
|
||||
function applyRemote(content) { if (content === editor.value) return; const start = editor.selectionStart, end = editor.selectionEnd; applyingRemote = true; editor.value = content; editor.setSelectionRange(Math.min(start, content.length), Math.min(end, content.length)); applyingRemote = false; render(); }
|
||||
function connect() {
|
||||
socket?.stop(); socket = new NoteSocket({ workspaceSlug, noteSlug, password,
|
||||
onStatus: state => setStatus(state === "online" ? "online" : state === "offline" ? "offline" : null, state === "online" ? "Połączono" : state === "offline" ? "Ponowne łączenie…" : "Łączenie…"),
|
||||
onAuthenticated: message => { if (passwordDialog.open) passwordDialog.close(); document.querySelector("#note-title").textContent = message.note_title; document.querySelector("#workspace-link").textContent = message.workspace_title; applyRemote(message.content); editor.focus(); },
|
||||
onDocument: message => { applyRemote(message.content); document.querySelector("#save-state").textContent = `Zapisano ${new Date(message.updated_at).toLocaleTimeString("pl-PL", { hour: "2-digit", minute: "2-digit" })}`; },
|
||||
onError: message => { document.querySelector("#password-error").textContent = message; if (info?.protected && !passwordDialog.open) passwordDialog.showModal(); }
|
||||
}); socket.connect();
|
||||
}
|
||||
async function initialize() {
|
||||
try { info = await api(`/api/workspaces/${encodeURIComponent(workspaceSlug)}/notes/${encodeURIComponent(noteSlug)}`); document.querySelector("#note-title").textContent = info.title; document.querySelector("#workspace-link").textContent = info.workspace_title; document.querySelector("#workspace-link").href = `/w/${encodeURIComponent(workspaceSlug)}`; document.querySelector("#back-workspace").href = `/w/${encodeURIComponent(workspaceSlug)}`; document.title = `${info.title} · ${info.workspace_title}`; applyUi({ write: true, replace: true }); if (info.protected && !password) passwordDialog.showModal(); else connect(); } catch (e) { document.body.innerHTML = `<main class="error-page"><div><h1>Nie znaleziono notatki</h1><p>${e.message}</p><a href="/w/${encodeURIComponent(workspaceSlug)}">Wróć do workspace</a></div></main>`; }
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-view]").forEach(button => button.addEventListener("click", () => { uiState = { ...uiState, view: button.dataset.view }; applyUi({ write: true }); }));
|
||||
modeToggle.addEventListener("click", () => { uiState = { ...uiState, mode: uiState.mode === "markdown" ? "text" : "markdown" }; applyUi({ write: true }); });
|
||||
window.addEventListener("popstate", () => { uiState = readEditorState(); applyUi(); });
|
||||
window.addEventListener("rustpad:urlchange", updateAddressLabel);
|
||||
document.querySelector("#copy-link").addEventListener("click", async () => { try { const url = currentShareUrl(uiState); await copyText(url); toast("Skopiowano link z widokiem"); } catch (e) { toast(e.message); } });
|
||||
document.querySelectorAll("[data-format]").forEach(button => button.addEventListener("click", () => applyFormat(editor, button.dataset.format)));
|
||||
editor.addEventListener("input", () => { render(); if (applyingRemote) return; clearTimeout(saveTimer); document.querySelector("#save-state").textContent = "Zapisywanie…"; saveTimer = setTimeout(() => socket?.update(editor.value), 250); });
|
||||
document.querySelector("#password-form").addEventListener("submit", event => { event.preventDefault(); password = document.querySelector("#open-password").value; setPassword(workspaceSlug, password); document.querySelector("#password-error").textContent = ""; connect(); });
|
||||
const historyPanel = document.querySelector("#history-panel"); document.querySelector("#history-button").addEventListener("click", async () => { historyPanel.setAttribute("aria-hidden", "false"); document.body.classList.add("history-open"); const list = document.querySelector("#history-list"); list.innerHTML = '<p class="empty">Ładowanie…</p>'; try { const revisions = await api(`/api/workspaces/${encodeURIComponent(workspaceSlug)}/notes/${encodeURIComponent(noteSlug)}/history`, { method: "POST", body: JSON.stringify({ password: password || null }) }); list.innerHTML = revisions.length ? revisions.map(r => `<article class="revision"><time>${new Date(r.created_at.replace(" ", "T") + "Z").toLocaleString("pl-PL")}</time><button class="secondary-button" data-revision="${r.id}">Przywróć</button></article>`).join("") : '<p class="empty">Brak historii.</p>'; list.querySelectorAll("[data-revision]").forEach(button => button.addEventListener("click", async () => { await api(`/api/workspaces/${encodeURIComponent(workspaceSlug)}/notes/${encodeURIComponent(noteSlug)}/restore`, { method: "POST", body: JSON.stringify({ password: password || null, revision_id: Number(button.dataset.revision) }) }); toast("Przywrócono wersję"); })); } catch (e) { list.innerHTML = `<p class="error">${e.message}</p>`; } });
|
||||
document.querySelector("#close-history").addEventListener("click", () => { historyPanel.setAttribute("aria-hidden", "true"); document.body.classList.remove("history-open"); });
|
||||
initialize();
|
||||
Reference in New Issue
Block a user