- 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>
46 lines
2.1 KiB
JavaScript
46 lines
2.1 KiB
JavaScript
(function () {
|
|
// 내장 툴바(toolbar: false)는 안 쓴다 — EasyMDE 기본 툴바 아이콘은 Font Awesome CDN을 전제로
|
|
// 하는데, 이 앱은 CDN을 안 쓰는 게 원칙이라 대신 journal.html/journal_day_detail.html에서
|
|
// 직접 만든 텍스트 버튼이 아래 EDITOR_ACTIONS로 EasyMDE 인스턴스 메서드를 호출한다.
|
|
function initEditors(root) {
|
|
if (typeof EasyMDE === "undefined") return;
|
|
var scope = root instanceof Element ? root : document;
|
|
var textareas = scope.querySelectorAll("textarea.markdown-editor:not([data-easymde-initialized])");
|
|
|
|
textareas.forEach(function (textarea) {
|
|
textarea.setAttribute("data-easymde-initialized", "true");
|
|
|
|
var easymde = new EasyMDE({
|
|
element: textarea,
|
|
toolbar: false,
|
|
spellChecker: false,
|
|
autoDownloadFontAwesome: false,
|
|
status: false,
|
|
placeholder: textarea.getAttribute("placeholder") || "",
|
|
minHeight: (textarea.getAttribute("rows") || 6) * 24 + "px",
|
|
// 글머리 목록 버튼/Enter 자동 이어쓰기가 기본 "*" 대신 "-"를 쓰게 한다.
|
|
// 서버 렌더링(app/markdown_utils.py)은 -/*/+ 전부 동일하게 처리하니 렌더링과는 무관하고
|
|
// 순수하게 에디터가 새로 만들어주는 글머리 기호에 대한 취향 설정이다.
|
|
unorderedListStyle: "-",
|
|
});
|
|
|
|
// CodeMirror는 원본 textarea와 실시간으로 값이 동기화되지 않는다(.save()를 명시적으로
|
|
// 불러야 함) — 매 변경마다 저장하고, htmx 미리보기(hx-trigger="input ...")와
|
|
// Alpine x-model이 둘 다 반응하도록 input 이벤트를 합성해서 던진다.
|
|
easymde.codemirror.on("change", function () {
|
|
easymde.codemirror.save();
|
|
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
});
|
|
|
|
textarea._easymde = easymde;
|
|
});
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
initEditors(document);
|
|
});
|
|
document.body.addEventListener("htmx:afterSwap", function (evt) {
|
|
initEditors(evt.target);
|
|
});
|
|
})();
|