Import .docx content directly into RTE editor as editable HTML
Instead of embedding an iframe, mammoth HTML is inserted straight into the contenteditable body so the admin can edit it like any other content. A download link to the original .docx sits above the content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
35ae40819b
commit
183bcf0ef2
2 files changed
+13
-32
No files matched your search
+7
-9
@@ -623,15 +623,13 @@ $('#import-go-btn').addEventListener('click', async () => {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: { base64, originalName: file.name },
|
body: { base64, originalName: file.name },
|
||||||
});
|
});
|
||||||
const embed = result.htmlUrl
|
const downloadLink = `<p><a href="${result.url}" download="${result.originalName}">⬇️ ${result.originalName}</a></p>`;
|
||||||
? `<details><summary>📄 ${result.originalName}</summary><iframe src="${result.htmlUrl}" style="width:100%;border:1px solid #ccc;border-radius:4px;margin-top:.5em;display:block;" onload="try{this.style.height=this.contentDocument.documentElement.scrollHeight+32+'px'}catch(e){this.style.height='500px'}"></iframe><p><a href="${result.url}" download="${result.originalName}">⬇️ Download ${result.originalName}</a></p></details>`
|
const content = result.htmlBody
|
||||||
: `<a href="${result.url}" target="_blank">📄 ${result.originalName}</a>`;
|
? downloadLink + result.htmlBody
|
||||||
if (type === 'assignment') {
|
: `<p><a href="${result.url}" target="_blank">📄 ${result.originalName}</a></p>`;
|
||||||
$('#ie-body-assignment').innerHTML += embed;
|
const editor = type === 'assignment' ? $('#ie-body-assignment') : $('#ie-body-lesson');
|
||||||
} else {
|
editor.innerHTML += content;
|
||||||
$('#ie-body-lesson').innerHTML += embed;
|
$('#import-status').textContent = '✅ Imported — content is now editable above.';
|
||||||
}
|
|
||||||
$('#import-status').textContent = '✅ File uploaded. Document embedded in body.';
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
$('#import-status').textContent = `❌ ${err.message}`;
|
$('#import-status').textContent = `❌ ${err.message}`;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1548,33 +1548,16 @@ app.post('/api/admin/upload-attachment', requirePin, async (req, res) => {
|
|||||||
return res.status(500).json({ error: `Could not save file: ${err.message}` });
|
return res.status(500).json({ error: `Could not save file: ${err.message}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to HTML for the iframe viewer
|
// Convert to HTML for inline editing in the RTE
|
||||||
let htmlUrl = null;
|
let htmlBody = null;
|
||||||
try {
|
try {
|
||||||
const { value: bodyHtml } = await mammoth.convertToHtml({ buffer });
|
const { value } = await mammoth.convertToHtml({ buffer });
|
||||||
const htmlFilename = `${uuid}.html`;
|
htmlBody = value || null;
|
||||||
const page = `<!doctype html><html><head><meta charset="utf-8">
|
|
||||||
<style>
|
|
||||||
*{box-sizing:border-box}
|
|
||||||
body{font-family:Georgia,serif;margin:0;padding:1rem 1.5rem;line-height:1.7;font-size:15px;font-weight:normal;color:#111}
|
|
||||||
p{margin:.6em 0;font-weight:normal}
|
|
||||||
strong,b{font-weight:bold}
|
|
||||||
h1{font-size:1.5em;margin:1em 0 .3em}
|
|
||||||
h2{font-size:1.25em;margin:.9em 0 .3em}
|
|
||||||
h3{font-size:1.1em;margin:.8em 0 .2em}
|
|
||||||
img{max-width:100%}
|
|
||||||
table{border-collapse:collapse;width:100%}
|
|
||||||
td,th{border:1px solid #ccc;padding:.4em .6em}
|
|
||||||
ul,ol{padding-left:1.5em}
|
|
||||||
</style>
|
|
||||||
</head><body>${bodyHtml}</body></html>`;
|
|
||||||
await writeFile(join(ATTACHMENTS_DIR, htmlFilename), page);
|
|
||||||
htmlUrl = `/api/attachments/${htmlFilename}`;
|
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// preview failed — download link still works
|
// conversion failed — download link still available
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.json({ url: `/api/attachments/${filename}`, htmlUrl, originalName });
|
return res.json({ url: `/api/attachments/${filename}`, htmlBody, originalName });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/health', (req, res) => res.json({ ok: true }));
|
app.get('/health', (req, res) => res.json({ ok: true }));
|
||||||
|
|||||||
Reference in new issue
Block a user