Dropping EasyMDE entirely (previous commit) fixed the Korean IME jamo split
but also removed the live markdown syntax highlighting everywhere, even on
platforms that never had the bug. Only iOS WebKit breaks CJK IME composition
under CodeMirror, so journal-editor.js now detects iOS (including the
desktop-UA-masquerading iPad, via MacIntel + multi-touch) and only skips
EasyMDE there, falling back to a native <textarea>. Everywhere else keeps
the full EasyMDE/CodeMirror editing experience as before.
window.JournalEditor now dispatches to the right engine per textarea
(checking t._easymde) so the toolbar buttons and the category-template
autofill in journal.html work unchanged regardless of which engine backs a
given textarea. Restores the easymde vendor files, base.html includes, and
service worker precache entries removed in the previous commit (cache
bumped to v8).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Forcing inputStyle to contenteditable (previous commit) didn't fix it on
iPhone, confirming this is CodeMirror 5's own long-standing weakness with
CJK IME composition on iOS WebKit, not just the iPad desktop-UA detection
issue. There's no reliable fix short of dropping CodeMirror for the journal
content field, so EasyMDE is removed entirely and the textarea goes back to
a native, uncontrolled <textarea> — nothing intercepts/re-renders it during
composition, so iOS's IME just works.
The markdown toolbar buttons (bold/italic/heading/quote/lists/code/link)
now manipulate the textarea's selection directly via a small JournalEditor
JS API instead of calling EasyMDE/CodeMirror commands, and image paste
tracks its upload placeholder by a unique text marker instead of a
CodeMirror bookmark. Also drops the vendored easymde.min.js/css (no longer
referenced) and bumps the service worker CACHE_NAME so stale cached copies
of the old vendor files get evicted.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
iPadOS 13+ sends a desktop Safari UA by default, which fools CodeMirror's mobile detection into using the more fragile textarea input mode. That, combined with CodeMirror repainting the line mid-composition, breaks Korean IME composition and leaves jamo unmerged. inputStyle can't be changed after the editor is created, so it must be set in the EasyMDE constructor options.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Paste-to-embed: pasting an image into the markdown editor uploads it and
inserts  at the cursor. Unlike gallery attachments these aren't
tied to a journal_entry (the entry may not exist yet while composing), so
they're stored per-user under app/media/journal/{user_id}/pasted/ with no
DB row, served through an ownership-scoped route, and never cleaned up
automatically when an entry is deleted -- an accepted tradeoff at this
app's personal scale.
- The markdown sanitizer was stripping all <img> tags (not on the bleach
allowlist), which would have silently deleted every pasted image on save;
added img/src/alt/title while keeping event-handler attributes blocked.
- Cap embedded image width in both the editor pane and the rendered preview
so a large pasted photo can't overflow its card.
- Fix real data loss risk found while testing this: docker-compose.yml had
no volume for app/media, so every container recreate during a deploy wiped
uploaded photos, and deploy_sftp.py was syncing app/media/ (runtime user
data, not source) into the remote build context. Added the volume mount
and excluded media/ from the sync script. Recovered and relocated the
real attachments that had already landed in the wrong place on the NAS
during earlier deploys this session.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replace the plain textarea with EasyMDE (vendored locally, no CDN) for
markdown authoring: syntax highlighting, smart list continuation, and a
custom text-based toolbar (built-in EasyMDE toolbar icons require Font
Awesome from a CDN, which this app doesn't use). unorderedListStyle is set
to "-" to match the app's own template convention.
- Add a preview/edit toggle button that swaps the editor for the exact same
server-rendered markdown (via /journal/preview) shown after saving, instead
of always showing both.
- Fix create/edit entry routes to verify the submitted category_id actually
belongs to the current user before inserting -- every other write path in
this app already checked ownership; this one didn't (found while manually
testing the new editor with a typo'd category id that happened to belong to
someone else's category, which surfaced as an IntegrityError 500 instead of
a clean 404-equivalent).
- Fix the default "일상" category template: bare "-" bullet lines don't parse
as list items in the markdown renderer (they need a trailing space), and
the content_template validator was silently stripping that trailing space
off on every save. Backfill migration updates any category still holding
the old, broken template text.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>