Add saving new note as draft, client-side only

This commit is contained in:
Adrian Gruntkowski 2025-02-08 17:27:36 +01:00
parent e1b8096447
commit b3ba84f54b
3 changed files with 63 additions and 15 deletions

View file

@ -553,6 +553,7 @@ class NoteForm extends HTMLElement {
this.note = {
type: "note",
content: "",
reminder: null,
};
}
@ -590,28 +591,24 @@ class NoteForm extends HTMLElement {
this.tasklistModeButton.addEventListener("click", (e) => {
e.preventDefault();
this.note.type = "tasklist";
this.#setContent();
this.#setNote("type", "tasklist");
this.#updateUI();
});
this.noteModeButton.addEventListener("click", (e) => {
e.preventDefault();
this.note.type = "note";
this.#setContent();
this.#setNote("type", "note");
this.#updateUI();
});
this.removeButton.addEventListener("click", (e) => {
e.preventDefault();
if (this.mode === "edit") {
this.dispatchEvent(
new CustomEvent("deleteNote", {
bubbles: true,
detail: this.note,
}),
);
}
this.dispatchEvent(
new CustomEvent("deleteNote", {
bubbles: true,
detail: this.note,
}),
);
this.#reset();
});
@ -630,7 +627,7 @@ class NoteForm extends HTMLElement {
});
this.addEventListener("reminderUpdate", () => {
this.note.reminder = this.reminderPicker.value;
this.#setNote("reminder", this.reminderPicker.value);
this.#updateUI();
});
@ -659,7 +656,7 @@ class NoteForm extends HTMLElement {
}
this.addEventListener("contentChange", () => {
this.note.content = this.content.firstChild.value;
this.#setNote("content", this.content.firstChild.value);
});
this.#updateUI();
@ -686,6 +683,23 @@ class NoteForm extends HTMLElement {
this.#setContent();
}
#setNote(field, value) {
this.note[field] = value;
if (field === "type") {
this.#setContent();
}
if (this.mode === "add") {
this.dispatchEvent(
new CustomEvent("updateDraft", {
bubbles: true,
detail: this.note,
}),
);
}
}
#updateUI() {
if (this.note.reminder?.enabled) {
this.reminderButtonLabel.textContent = reminderLabel(this.note.reminder);

View file

@ -47,7 +47,7 @@ if (URL_PARAMS.has("reset-meta")) {
}
// Very rudimentary periodic sync. It will be refactored into a more real-time
// solution using either websocket of long-polling, so that server can notify about
// solution using either websocket or long-polling, so that server can notify about
// new data to sync.
const sync = async () => {
await Notes.sync();
@ -99,6 +99,9 @@ const newNote = document.querySelector("#new-note");
const editNote = document.querySelector("#edit-note");
const editNoteDialog = document.querySelector("#edit-note-dialog");
// Load draft into new note
newNote.load(structuredClone(await Notes.getDraft()));
// Each save event originating from storage triggers a re-render
// of notes list.
Notes.addEventListener("save", render.bind(this));
@ -112,9 +115,18 @@ if (isLoggedIn) {
// note-form component specific event handlers
newNote.addEventListener("addNote", async (e) => {
await Notes.add(e.detail);
await Notes.clearDraft();
Notes.saveStorage();
});
newNote.addEventListener("updateDraft", async (e) => {
await Notes.setDraft(e.detail);
});
newNote.addEventListener("deleteNote", async (e) => {
await Notes.clearDraft();
});
editNote.addEventListener("updateNote", async (e) => {
await Notes.update(e.detail);
Notes.saveStorage();

View file

@ -116,6 +116,13 @@ class WebNoteStore {
}
}
const draftTemplate = {
id: "draft",
type: "note",
content: "",
reminder: null,
};
export class SyncedNoteStore extends EventTarget {
constructor(dbName, endpoint, webStore) {
super();
@ -171,6 +178,21 @@ export class SyncedNoteStore extends EventTarget {
return memory[this.dbName][this.storeName][id];
}
async getDraft() {
return this.get("draft").then(
(draft) => draft || structuredClone(draftTemplate),
);
}
async setDraft(draft) {
draft.id = "draft";
return this.update(draft, true);
}
async clearDraft() {
return this.update(structuredClone(draftTemplate), true);
}
async getMeta() {
return this.get("meta").then((meta) => meta || { lastSync: null });
}