Fix line breaks in AI output: use innerHTML instead of textContent
Adds setOutputText() helper that escapes HTML and converts \n to <br>, applied to all AI-generated note outputs so line breaks are preserved in contenteditable divs. Also cleans up CSS for quiz option markers.
This commit is contained in:
parent
7eb72cee78
commit
ca68177abb
10 changed files with 26 additions and 17 deletions
|
|
@ -439,7 +439,7 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
|
|||
.shadess-flag-btn{font-size:11px;padding:2px 6px;}
|
||||
|
||||
/* Settings page */
|
||||
.settings-page{display:flex;flex-direction:column;gap:0;max-width:800px;}
|
||||
.settings-page{display:flex;flex-direction:column;gap:0;}
|
||||
.settings-page .settings-section{padding:20px;margin-bottom:12px;border-radius:var(--radius);}
|
||||
.settings-page .settings-section h3{font-size:16px;font-weight:700;color:var(--g800);margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--g100);display:flex;align-items:center;gap:8px;}
|
||||
.settings-page .settings-section p{font-size:13px;color:var(--g600);margin-bottom:12px;line-height:1.6;}
|
||||
|
|
@ -548,10 +548,7 @@ body{font-family:'Inter',system-ui,sans-serif;background:var(--g50);color:var(--
|
|||
.lh-quiz-option input[type="radio"]{accent-color:var(--blue);width:18px;height:18px;flex-shrink:0;}
|
||||
.lh-quiz-option span{flex:1;}
|
||||
.lh-opt-correct{border-color:var(--green) !important;background:var(--green-light) !important;box-shadow:0 0 0 2px rgba(16,185,129,0.2) !important;}
|
||||
.lh-opt-correct::after{content:'\\2713';position:absolute;right:14px;color:var(--green);font-weight:700;font-size:18px;}
|
||||
.lh-quiz-option.lh-opt-correct,.lh-quiz-option.lh-opt-wrong{position:relative;}
|
||||
.lh-opt-wrong{border-color:var(--red) !important;background:var(--red-light) !important;box-shadow:0 0 0 2px rgba(239,68,68,0.2) !important;}
|
||||
.lh-opt-wrong::after{content:'\\2717';position:absolute;right:14px;color:var(--red);font-weight:700;font-size:18px;}
|
||||
|
||||
/* Quiz results */
|
||||
.lh-result-item{margin-bottom:14px;padding-bottom:14px;border-bottom:1px solid var(--g100);}
|
||||
|
|
|
|||
|
|
@ -223,6 +223,18 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
// GLOBAL FUNCTIONS (must be outside DOMContentLoaded)
|
||||
// ============================================================
|
||||
|
||||
// ── Set formatted text on output/contenteditable elements ──
|
||||
// Converts \n to <br> so line breaks survive in contenteditable divs
|
||||
// and are preserved when copying with innerText
|
||||
function setOutputText(el, text) {
|
||||
if (!el) return;
|
||||
if (typeof el === 'string') el = document.getElementById(el);
|
||||
if (!el) return;
|
||||
// Escape HTML, then convert newlines to <br>
|
||||
var safe = String(text || '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
el.innerHTML = safe.replace(/\n/g, '<br>');
|
||||
}
|
||||
|
||||
// ── Announcement banner ────────────────────────────────────
|
||||
function loadAnnouncement() {
|
||||
fetch('/api/admin/config/announcement', { headers: getAuthHeaders() })
|
||||
|
|
@ -457,7 +469,7 @@ function refineDocument(outputElementId, inputElementId) {
|
|||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) { doc.textContent = data.refined; input.value = ''; showToast('Refined!', 'success'); }
|
||||
if (data.success) { setOutputText(doc, data.refined); input.value = ''; showToast('Refined!', 'success'); }
|
||||
else showToast(data.error || 'Failed', 'error');
|
||||
})
|
||||
.catch(function(err) { hideLoading(); showToast(err.message, 'error'); });
|
||||
|
|
@ -476,7 +488,7 @@ function shortenDocument(outputElementId) {
|
|||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) { doc.textContent = data.shortened; showToast('Shortened!', 'success'); }
|
||||
if (data.success) { setOutputText(doc, data.shortened); showToast('Shortened!', 'success'); }
|
||||
else showToast(data.error || 'Failed', 'error');
|
||||
})
|
||||
.catch(function(err) { hideLoading(); showToast(err.message, 'error'); });
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
reviewText.textContent = data.review;
|
||||
setOutputText(reviewText, data.review);
|
||||
modelTag.textContent = (data.model || '').split('/').pop();
|
||||
outputCard.classList.remove('hidden');
|
||||
outputCard.scrollIntoView({ behavior: 'smooth' });
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
courseText.textContent = data.hospitalCourse;
|
||||
setOutputText(courseText, data.hospitalCourse);
|
||||
formatTag.textContent = data.format || '';
|
||||
modelTag.textContent = (data.model || '').split('/').pop();
|
||||
outputCard.classList.remove('hidden');
|
||||
|
|
@ -183,7 +183,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
clarifyOutput.textContent = data.questions;
|
||||
setOutputText(clarifyOutput, data.questions);
|
||||
clarifyOutput.classList.remove('hidden');
|
||||
showToast('Review missing information below', 'info');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
hpiText.textContent = data.hpi;
|
||||
setOutputText(hpiText, data.hpi);
|
||||
modelTag.textContent = (data.model || '').split('/').pop();
|
||||
outputCard.classList.remove('hidden');
|
||||
outputCard.scrollIntoView({ behavior: 'smooth' });
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
narrativeText.textContent = data.narrative;
|
||||
setOutputText(narrativeText, data.narrative);
|
||||
modelTag.textContent = (data.model || '').split('/').pop();
|
||||
if (data.summary) {
|
||||
summaryBar.innerHTML = '<div class="stat"><span class="dot dot-green"></span> Achieved: ' + data.summary.achieved + '</div>' +
|
||||
|
|
@ -172,7 +172,7 @@
|
|||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="fas fa-compress"></i> Regenerate Summary';
|
||||
if (data.success) {
|
||||
document.getElementById('ms-summary-text').textContent = data.summary;
|
||||
setOutputText('ms-summary-text', data.summary);
|
||||
document.getElementById('ms-quick-summary').classList.remove('hidden');
|
||||
showToast('Summary generated!', 'success');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,7 +366,7 @@
|
|||
var out = document.getElementById('shadess-result-text');
|
||||
var outCard = document.getElementById('shadess-output');
|
||||
var tag = document.getElementById('shadess-model-tag');
|
||||
if (out) out.textContent = data.assessment;
|
||||
if (out) setOutputText(out, data.assessment);
|
||||
if (tag) tag.textContent = (data.model || '').split('/').pop();
|
||||
if (outCard) { outCard.classList.remove('hidden'); outCard.scrollIntoView({ behavior: 'smooth' }); }
|
||||
showToast('SSHADESS assessment generated', 'success');
|
||||
|
|
@ -861,7 +861,7 @@
|
|||
var noteEl = document.getElementById('wv-note-text');
|
||||
var outCard = document.getElementById('wv-note-output');
|
||||
var tag = document.getElementById('wv-note-model-tag');
|
||||
if (noteEl) noteEl.textContent = data.note;
|
||||
if (noteEl) setOutputText(noteEl, data.note);
|
||||
if (tag) tag.textContent = (data.model || '').split('/').pop();
|
||||
if (outCard) { outCard.classList.remove('hidden'); outCard.scrollIntoView({ behavior: 'smooth' }); }
|
||||
showToast('Well visit note generated!', 'success');
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@
|
|||
var noteEl = document.getElementById('sick-note-text');
|
||||
var outCard = document.getElementById('sick-note-output');
|
||||
var tag = document.getElementById('sick-note-model-tag');
|
||||
if (noteEl) noteEl.textContent = data.note;
|
||||
if (noteEl) setOutputText(noteEl, data.note);
|
||||
if (tag) tag.textContent = (data.model || '').split('/').pop();
|
||||
if (outCard) { outCard.classList.remove('hidden'); outCard.scrollIntoView({ behavior: 'smooth' }); }
|
||||
showToast('Sick visit note generated!', 'success');
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
soapText.textContent = data.soap;
|
||||
setOutputText(soapText, data.soap);
|
||||
modelTag.textContent = (data.model || '').split('/').pop();
|
||||
outputCard.classList.remove('hidden');
|
||||
outputCard.scrollIntoView({ behavior: 'smooth' });
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@
|
|||
.then(function(data) {
|
||||
hideLoading();
|
||||
if (data.success) {
|
||||
hpiText.textContent = data.hpi || data.soap;
|
||||
setOutputText(hpiText, data.hpi || data.soap);
|
||||
modelTag.textContent = (data.model || '').split('/').pop();
|
||||
outputCard.classList.remove('hidden');
|
||||
outputCard.scrollIntoView({ behavior: 'smooth' });
|
||||
|
|
|
|||
Loading…
Reference in a new issue