destroy learning hub row editors

This commit is contained in:
Daniel 2026-05-08 09:05:13 +02:00
parent a0ba8c16c1
commit 13c4c0a1a0
2 changed files with 45 additions and 6 deletions

View file

@ -117,7 +117,7 @@
// Remove question block
var rmQ = e.target.closest('.lh-rm-question');
if (rmQ) { var qb = rmQ.closest('.lh-question-block'); if (qb) qb.remove(); return; }
if (rmQ) { var qb = rmQ.closest('.lh-question-block'); if (qb) { destroyQuestionBlockEditors(qb); qb.remove(); } return; }
// Add option to question
var addOpt = e.target.closest('.lh-add-option');
@ -129,7 +129,7 @@
// Remove option
var rmOpt = e.target.closest('.lh-rm-option');
if (rmOpt) { var row = rmOpt.closest('.lh-option-row'); if (row) row.remove(); return; }
if (rmOpt) { var row = rmOpt.closest('.lh-option-row'); if (row) { destroyOptionEditor(row); row.remove(); } return; }
});
// wireSearch() called after component is in DOM
@ -876,7 +876,7 @@
// Fill questions if any were generated alongside slides
var qContainerP = document.getElementById('lh-cms-questions');
if (qContainerP) {
qContainerP.innerHTML = '';
clearQuestionBlocks(qContainerP);
if (content.questions && Array.isArray(content.questions)) {
content.questions.forEach(function(q) { addQuestionBlock(q); });
}
@ -898,7 +898,7 @@
// Replace questions
var qContainer = document.getElementById('lh-cms-questions');
if (qContainer) {
qContainer.innerHTML = '';
clearQuestionBlocks(qContainer);
if (content.questions && Array.isArray(content.questions)) {
content.questions.forEach(function(q) { addQuestionBlock(q); });
}
@ -1240,6 +1240,29 @@
return (html === '<p></p>' || html === '') ? '' : html;
}
function destroyTpEditor(editor) {
if (editor && typeof editor.destroy === 'function') editor.destroy();
}
function destroyOptionEditor(row) {
if (!row || !row._optEditor) return;
destroyTpEditor(row._optEditor);
row._optEditor = null;
}
function destroyQuestionBlockEditors(block) {
if (!block) return;
destroyTpEditor(block._questionEditor);
block._questionEditor = null;
block.querySelectorAll('.lh-option-row').forEach(destroyOptionEditor);
}
function clearQuestionBlocks(container) {
if (!container) return;
container.querySelectorAll('.lh-question-block').forEach(destroyQuestionBlockEditors);
container.innerHTML = '';
}
// ── Body editor ────────────────────────────────────────────
function initBodyEditor() {
var wrap = document.getElementById('lh-body-editor');
@ -1335,7 +1358,7 @@
document.getElementById('lh-cms-edit-category').value = '';
document.getElementById('lh-cms-edit-type').value = contentType || 'article';
document.getElementById('lh-cms-edit-published').value = 'false';
document.getElementById('lh-cms-questions').innerHTML = '';
clearQuestionBlocks(document.getElementById('lh-cms-questions'));
document.getElementById('btn-lh-delete-content').classList.add('hidden');
hideDeleteConfirm();
toggleEditorMode(contentType || 'article');
@ -1375,7 +1398,7 @@
// Load questions
var qContainer = document.getElementById('lh-cms-questions');
qContainer.innerHTML = '';
clearQuestionBlocks(qContainer);
if (c.questions && c.questions.length > 0) {
c.questions.forEach(function(q) { addQuestionBlock(q); });
}

View file

@ -0,0 +1,16 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const source = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'learningHub.js'), 'utf8');
test('Learning Hub destroys embedded Tiptap editors before removing CMS rows', () => {
assert.match(source, /function destroyTpEditor\(editor\)/);
assert.match(source, /function destroyQuestionBlockEditors\(block\)/);
assert.match(source, /function clearQuestionBlocks\(container\)/);
assert.match(source, /destroyQuestionBlockEditors\(qb\); qb\.remove\(\)/);
assert.match(source, /destroyOptionEditor\(row\); row\.remove\(\)/);
assert.doesNotMatch(source, /document\.getElementById\('lh-cms-questions'\)\.innerHTML = ''/);
assert.doesNotMatch(source, /qContainer\.innerHTML = ''/);
});