function copyToClipboard(element) { if (!element) return; const messageElement = element.closest(".message, .user-message, .assistant-message"); if (!messageElement) return; const rawText = messageElement.getAttribute("data-raw"); if (!rawText) return; navigator.clipboard.writeText(rawText).then(function() { const originalSvg = element.innerHTML; element.innerHTML = ""; setTimeout(() => { element.innerHTML = originalSvg; }, 1000); }).catch(function(err) { console.error("Failed to copy text: ", err); }); } function branchHere(element) { if (!element) return; const messageElement = element.closest(".message, .user-message, .assistant-message"); if (!messageElement) return; const index = messageElement.getAttribute("data-index"); if (!index) return; const branchIndexInput = document.getElementById("Branch-index").querySelector("input"); if (!branchIndexInput) { console.error("Element with ID 'Branch-index' not found."); return; } const branchButton = document.getElementById("Branch"); if (!branchButton) { console.error("Required element 'Branch' not found."); return; } branchIndexInput.value = index; // Trigger any 'change' or 'input' events Gradio might be listening for const event = new Event("input", { bubbles: true }); // 'change' might also work branchIndexInput.dispatchEvent(event); branchButton.click(); // Gradio will now pick up the 'index' } function regenerateClick() { document.getElementById("Regenerate").click(); } function continueClick() { document.getElementById("Continue").click(); } function removeLastClick() { document.getElementById("Remove-last").click(); } // === Version navigation handled in main.js === // function handleMorphdomUpdate(text) { // Track open blocks const openBlocks = new Set(); document.querySelectorAll(".thinking-block").forEach(block => { const blockId = block.getAttribute("data-block-id"); // If block exists and is open, add to open set if (blockId && block.hasAttribute("open")) { openBlocks.add(blockId); } }); // Store scroll positions for any open blocks const scrollPositions = {}; document.querySelectorAll(".thinking-block[open]").forEach(block => { const content = block.querySelector(".thinking-content"); const blockId = block.getAttribute("data-block-id"); if (content && blockId) { const isAtBottom = Math.abs((content.scrollHeight - content.scrollTop) - content.clientHeight) < 5; scrollPositions[blockId] = { position: content.scrollTop, isAtBottom: isAtBottom }; } }); morphdom( document.getElementById("chat").parentNode, "
" + text + "
", { onBeforeElUpdated: function(fromEl, toEl) { // Preserve code highlighting if (fromEl.tagName === "PRE" && fromEl.querySelector("code[data-highlighted]")) { const fromCode = fromEl.querySelector("code"); const toCode = toEl.querySelector("code"); if (fromCode && toCode && fromCode.textContent === toCode.textContent) { toEl.className = fromEl.className; toEl.innerHTML = fromEl.innerHTML; return false; } } // For thinking blocks, assume closed by default if (fromEl.classList && fromEl.classList.contains("thinking-block") && toEl.classList && toEl.classList.contains("thinking-block")) { const blockId = toEl.getAttribute("data-block-id"); // Remove open attribute by default toEl.removeAttribute("open"); // If this block was explicitly opened by user, keep it open if (blockId && openBlocks.has(blockId)) { toEl.setAttribute("open", ""); } } return !fromEl.isEqualNode(toEl); }, onElUpdated: function(el) { // Restore scroll positions for open thinking blocks if (el.classList && el.classList.contains("thinking-block") && el.hasAttribute("open")) { const blockId = el.getAttribute("data-block-id"); const content = el.querySelector(".thinking-content"); if (content && blockId && scrollPositions[blockId]) { setTimeout(() => { if (scrollPositions[blockId].isAtBottom) { content.scrollTop = content.scrollHeight; } else { content.scrollTop = scrollPositions[blockId].position; } }, 0); } } } } ); // Add toggle listeners for new blocks document.querySelectorAll(".thinking-block").forEach(block => { if (!block._hasToggleListener) { block.addEventListener("toggle", function(e) { if (this.open) { const content = this.querySelector(".thinking-content"); if (content) { setTimeout(() => { content.scrollTop = content.scrollHeight; }, 0); } } }); block._hasToggleListener = true; } }); }