diff --git a/public/admin.html b/public/admin.html index f99c084..d0a459d 100644 --- a/public/admin.html +++ b/public/admin.html @@ -181,7 +181,7 @@

-
+
Lesson content
@@ -195,16 +195,33 @@ - - + +
-
- - +
+
Instructions
+
+ + + + + + + + + + + + + +
+
+
diff --git a/public/admin.js b/public/admin.js index 031d315..8f758f0 100644 --- a/public/admin.js +++ b/public/admin.js @@ -395,7 +395,7 @@ async function openItemEditor(unitId, itemId) { $('#ie-type').value = item.type; $('#ie-title').value = item.title; $('#ie-body-lesson').innerHTML = item.body || ''; - $('#ie-body-assignment').value = item.body; + $('#ie-body-assignment').innerHTML = item.body || ''; $('#ie-points').value = item.points || 10; $('#ie-due-date').value = item.due_date || ''; $('#ie-allow-retakes').checked = !!item.allow_retakes; @@ -417,7 +417,7 @@ async function openItemEditor(unitId, itemId) { $('#ie-type').value = 'lesson'; $('#ie-title').value = ''; $('#ie-body-lesson').innerHTML = ''; - $('#ie-body-assignment').value = ''; + $('#ie-body-assignment').innerHTML = ''; $('#ie-points').value = 10; $('#ie-due-date').value = ''; $('#ie-allow-retakes').checked = false; @@ -446,57 +446,60 @@ $('#ie-type').addEventListener('change', updateItemFieldVisibility); // ---------- rich text editor (lesson body) ---------- -function getLessonBody() { - const html = $('#ie-body-lesson').innerHTML.trim(); +function getRteBody(el) { + const html = el.innerHTML.trim(); return html === '
' ? '' : html; } +function getLessonBody() { return getRteBody($('#ie-body-lesson')); } +function getAssignmentBody() { return getRteBody($('#ie-body-assignment')); } -let rtesavedRange = null; - -// Save selection whenever the editor loses focus (e.g. when clicking a toolbar button) -$('#ie-body-lesson').addEventListener('blur', () => { - const sel = window.getSelection(); - rtesavedRange = sel.rangeCount > 0 ? sel.getRangeAt(0).cloneRange() : null; -}); - -function rteRestoreAndExec(cmd, val = null) { - $('#ie-body-lesson').focus(); - if (rtesavedRange) { - const sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(rtesavedRange); - } - document.execCommand(cmd, false, val); -} - -// Format buttons (bold, italic, heading, lists, etc.) +// Format buttons β€” mousedown+preventDefault keeps focus/selection in the editor document.querySelectorAll('.rte-btn[data-cmd]').forEach((btn) => { - btn.addEventListener('click', () => { - rteRestoreAndExec(btn.dataset.cmd, btn.dataset.val || null); + btn.addEventListener('mousedown', (e) => { + e.preventDefault(); + const editor = btn.closest('.rte-group').querySelector('.rte-editor'); + editor.focus(); + document.execCommand(btn.dataset.cmd, false, btn.dataset.val || null); }); }); -// Link button -$('#rte-link-btn').addEventListener('click', () => { - const savedRange = rtesavedRange; - const url = prompt('Enter URL (e.g. https://example.com):'); - if (url) { - rteRestoreAndExec('createLink', url); - } +// Link buttons +document.querySelectorAll('.rte-link-btn').forEach((btn) => { + btn.addEventListener('mousedown', (e) => { + e.preventDefault(); + const editor = btn.closest('.rte-group').querySelector('.rte-editor'); + editor.focus(); + const sel = window.getSelection(); + const savedRange = sel.rangeCount > 0 ? sel.getRangeAt(0).cloneRange() : null; + const url = prompt('Enter URL (e.g. https://example.com):'); + if (url) { + editor.focus(); + if (savedRange) { sel.removeAllRanges(); sel.addRange(savedRange); } + document.execCommand('createLink', false, url); + } + }); }); -// YouTube embed button -$('#rte-youtube-btn').addEventListener('click', () => { - const input = prompt('YouTube URL or video ID:'); - if (!input) return; - const match = input.match(/(?:youtu\.be\/|youtube\.com\/(?:embed\/|watch\?v=))([a-zA-Z0-9_-]{11})/); - const id = match ? match[1] : input.trim(); - if (id) { - rteRestoreAndExec( - 'insertHTML', - `

` - ); - } +// YouTube embed buttons +document.querySelectorAll('.rte-youtube-btn').forEach((btn) => { + btn.addEventListener('mousedown', (e) => { + e.preventDefault(); + const editor = btn.closest('.rte-group').querySelector('.rte-editor'); + editor.focus(); + const sel = window.getSelection(); + const savedRange = sel.rangeCount > 0 ? sel.getRangeAt(0).cloneRange() : null; + const input = prompt('YouTube URL or video ID:'); + if (!input) return; + const match = input.match(/(?:youtu\.be\/|youtube\.com\/(?:embed\/|watch\?v=))([a-zA-Z0-9_-]{11})/); + const id = match ? match[1] : input.trim(); + if (id) { + editor.focus(); + if (savedRange) { sel.removeAllRanges(); sel.addRange(savedRange); } + document.execCommand('insertHTML', false, + `

` + ); + } + }); }); // ---------- scan a page (photo -> lesson/quiz content via local Ollama) ---------- @@ -624,8 +627,7 @@ $('#import-go-btn').addEventListener('click', async () => { ? `
πŸ“„ ${result.originalName}

⬇️ Download ${result.originalName}

` : `πŸ“„ ${result.originalName}`; if (type === 'assignment') { - const cur = $('#ie-body-assignment').value; - $('#ie-body-assignment').value = cur ? cur + '\n\n' + embed : embed; + $('#ie-body-assignment').innerHTML += embed; } else { $('#ie-body-lesson').innerHTML += embed; } @@ -691,7 +693,7 @@ $('#item-form').addEventListener('submit', async (e) => { unitId: Number($('#ie-unit-id').value), type, title, - body: type === 'lesson' ? getLessonBody() : type === 'assignment' ? $('#ie-body-assignment').value : '', + body: type === 'lesson' ? getLessonBody() : type === 'assignment' ? getAssignmentBody() : '', points: type === 'assignment' ? Number($('#ie-points').value) || 0 : 0, refId: type === 'spelling_practice' || type === 'spelling_test' ? Number($('#ie-list').value) : type === 'flashcards' ? Number($('#ie-deck').value) : null,