From 7651ea620c785c03abd32c34febb030439cd7916 Mon Sep 17 00:00:00 2001 From: gramps Date: Wed, 1 Jul 2026 18:01:42 -0700 Subject: [PATCH] v1.8.8 -> v1.8.9: fix copy button with execCommand fallback for insecure context --- config.py | 2 +- templates/index.html | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/config.py b/config.py index ec9ef98..b07a605 100644 --- a/config.py +++ b/config.py @@ -9,7 +9,7 @@ import logging log = logging.getLogger("jarvischat") -VERSION = "v1.8.8" +VERSION = "v1.8.9" OLLAMA_BASE = os.environ.get("OLLAMA_BASE", "http://localhost:11434") LLAMA_SERVER_BASE = os.environ.get("LLAMA_SERVER_BASE", "http://192.168.50.108:8081") SEARXNG_BASE = "http://localhost:8888" diff --git a/templates/index.html b/templates/index.html index d640301..d4736a1 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1258,7 +1258,12 @@ function addCopyButtons(msgDiv) { const btn = document.createElement('button'); btn.className = 'copy-btn'; btn.textContent = 'copy'; - btn.onclick = () => navigator.clipboard.writeText(pre.querySelector('code')?.textContent || pre.textContent).then(() => { btn.textContent = 'copied!'; setTimeout(() => btn.textContent = 'copy', 1500); }); + btn.onclick = () => { + const text = pre.querySelector('code')?.textContent || pre.textContent; + if (navigator.clipboard) { + navigator.clipboard.writeText(text).then(() => { btn.textContent = 'copied!'; setTimeout(() => btn.textContent = 'copy', 1500); }).catch(() => fallbackCopy(text, btn)); + } else { fallbackCopy(text, btn); } + }; pre.style.position = 'relative'; pre.appendChild(btn); }); @@ -1266,6 +1271,18 @@ function addCopyButtons(msgDiv) { function escapeHtml(t) { const d = document.createElement('div'); d.textContent = t; return d.innerHTML; } function scrollToBottom() { const c = document.getElementById('chatContainer'); c.scrollTop = c.scrollHeight; } +function fallbackCopy(text, btn) { + const ta = document.createElement('textarea'); + ta.value = text; + ta.style.position = 'fixed'; + ta.style.opacity = '0'; + document.body.appendChild(ta); + ta.select(); + document.execCommand('copy'); + document.body.removeChild(ta); + btn.textContent = 'copied!'; + setTimeout(() => btn.textContent = 'copy', 1500); +} const userInput = document.getElementById('userInput'); userInput.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = Math.min(this.scrollHeight, 200) + 'px'; });