c54ae32c7d48
treat markup-only or zero-width contenteditable bodies as blank so a new note with nothing typed is never saved
- time
- 2026-08-13 19:25 UTC · 2 months ago
- machine
- koh2
- agent
- deepseek-v4-flash
- session
- blank note guard
- parent
- 2adb75e4873e
↓ peach-browser-c54ae32c.tar.gzatlas at this save
files changed1 file
src/popup/views/NotesEditor.tsx+12 −2src/popup/views/NotesEditor.tsx+12 −2
@@ -33,6 +33,16 @@3333 let saveTimer: number | null = null;3434 let savedFadeTimer: number | null = null;3535 36+ // An "empty" contenteditable body frequently serialises to "<br>", a37+ // zero-width space, , or whitespace-only markup rather than "". Trim38+ // alone can't catch those, so strip tags/entities/formatting and check for39+ // any actual visible character before deciding a note has content.40+ function bodyIsBlank(html: string): boolean {41+ return !html42+ .replace(/<[^>]*>| | |\u200b|\ufeff/g, "")43+ .replace(/\s+/g, "");44+ }45+3646 function scheduleAutosave() {3747 setDirty(true);3848 if (saveTimer) clearTimeout(saveTimer);@@ -43,7 +53,7 @@4353 const t = title();4454 const b = body();4555 // Don't save if genuinely empty (new note, nothing typed)46- if (!t.trim() && !b.trim()) return;56+ if (!t.trim() && bodyIsBlank(b)) return;4757 const res = await sendMessage({4858 type: "SAVE_NOTE",4959 payload: { id: noteId(), title: t || "Untitled", body: b },@@ -71,7 +81,7 @@7181 async function handleBack() {7282 // Await the final save before navigating away — fire-and-forget would let7383 // the component unmount before the message round-trip completes.74- if (dirty() && (title().trim() || body().trim())) {84+ if (dirty() && (title().trim() || !bodyIsBlank(body()))) {7585 if (saveTimer) { clearTimeout(saveTimer); saveTimer = null; }7686 await save();7787 }