diff --git a/public/assets/js/base.js b/public/assets/js/base.js index ab78e62..c3e9384 100644 --- a/public/assets/js/base.js +++ b/public/assets/js/base.js @@ -13,6 +13,17 @@ document.addEventListener('DOMContentLoaded', () => { return DOMPurify.sanitize(marked.parse(text)); } + function enhanceChatLinks(container = chatEl) { + if (!container) { + return; + } + + container.querySelectorAll('a[href]').forEach((link) => { + link.setAttribute('target', '_blank'); + link.setAttribute('rel', 'noopener noreferrer'); + }); + } + function addMessage(role, html = '', extra = '') { const msg = document.createElement('div'); msg.className = 'message ' + role; @@ -23,6 +34,9 @@ document.addEventListener('DOMContentLoaded', () => { msg.appendChild(bubble); chatEl.appendChild(msg); + + enhanceChatLinks(bubble); + chatEl.scrollTop = chatEl.scrollHeight; return bubble; @@ -182,6 +196,7 @@ document.addEventListener('DOMContentLoaded', () => { function renderBubbleContent(bubble, raw) { bubble.innerHTML = renderMarkdown(raw); cleanupThinkSpans(bubble); + enhanceChatLinks(bubble); chatEl.scrollTop = chatEl.scrollHeight; } @@ -191,6 +206,7 @@ document.addEventListener('DOMContentLoaded', () => { if (!res.ok) return; const messages = await res.json(); messages.forEach(m => addMessage(m.role, renderMarkdown(m.text))); + enhanceChatLinks(chatEl); } catch {} } @@ -288,6 +304,7 @@ document.addEventListener('DOMContentLoaded', () => { } } catch { bubble.innerHTML += '
Error occurred.'; + enhanceChatLinks(bubble); } finally { if (renderTimer) { clearTimeout(renderTimer);