(function () { "use strict"; const MARKDOWN_IT_CDN = "https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"; const HIGHLIGHT_JS_CDN = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"; const HIGHLIGHT_LANG_GO_CDN = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/go.min.js"; const HIGHLIGHT_LANG_RUST_CDN = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/rust.min.js"; const HIGHLIGHT_LANG_TS_CDN = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/typescript.min.js"; const EDITOR_BUTTON_ID = "custom-markdown-edit-btn"; const MODAL_ID = "markdown-editor-modal"; const CHAT_INPUT_SELECTOR = "#chat-input"; const VOICE_BUTTON_SELECTOR = "#voice-input-button"; let md; let hljs; let editorModal = null; let editorInput = null; let markdownPreview = null; let mainChatInput = null; let mouseDownTarget = null; function loadScript(src) { return new Promise((resolve, reject) => { if (document.querySelector(`script[src="${src}"]`)) { resolve(); return; } const script = document.createElement("script"); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } async function ensureDependencies() { try { if (typeof window.markdownit === "undefined") { await loadScript(MARKDOWN_IT_CDN); } if (typeof window.hljs === "undefined") { await loadScript(HIGHLIGHT_JS_CDN); await Promise.all([ loadScript(HIGHLIGHT_LANG_GO_CDN), loadScript(HIGHLIGHT_LANG_RUST_CDN), loadScript(HIGHLIGHT_LANG_TS_CDN), ]).catch((e) => console.warn("Could not load optional highlight.js languages:", e) ); } md = window.markdownit({ html: true, linkify: true, typographer: true, highlight: function (str, lang) { if (window.hljs) { hljs = window.hljs; if (lang && hljs.getLanguage(lang)) { try { return ( '
' +
                  hljs.highlight(str, { language: lang, ignoreIllegals: true })
                    .value +
                  "
" ); } catch (__) {} } try { return ( '
' +
                hljs.highlightAuto(str).value +
                "
" ); } catch (__) {} } return ( '
' +
            md.utils.escapeHtml(str) +
            "
" ); }, }); hljs = window.hljs; console.log("Markdown Editor Dependencies loaded."); } catch (error) { console.error("Failed to load Markdown editor dependencies:", error); } } function createModal() { if (document.getElementById(MODAL_ID)) { return document.getElementById(MODAL_ID); } const modalHTML = `
Markdown编辑器
`; const modalDiv = document.createElement("div"); modalDiv.id = MODAL_ID; modalDiv.innerHTML = modalHTML; document.body.appendChild(modalDiv); editorModal = modalDiv; editorInput = modalDiv.querySelector(".editor-input"); markdownPreview = modalDiv.querySelector(".markdown-preview"); const closeBtn = modalDiv.querySelector(".close-btn"); const applyBtn = modalDiv.querySelector(".apply-btn"); closeBtn.addEventListener("click", closeModal); applyBtn.addEventListener("click", applyChanges); editorInput.addEventListener("input", updatePreview); modalDiv.addEventListener("mousedown", (e) => { if (e.target === modalDiv) { mouseDownTarget = e.target; } else { mouseDownTarget = null; } }); modalDiv.addEventListener("mouseup", (e) => { if (e.target === modalDiv && mouseDownTarget === modalDiv) { closeModal(); } mouseDownTarget = null; }); return modalDiv; } function openModal() { if (!md || !hljs) { console.error("Markdown editor dependencies not ready."); alert("编辑器依赖未能加载,请检查网络连接或控制台错误。"); return; } if (!mainChatInput) { mainChatInput = document.querySelector(CHAT_INPUT_SELECTOR); if (!mainChatInput) { console.error("Chat input element not found when opening modal."); return; } } editorModal = createModal(); const currentText = (mainChatInput.innerText || "").trim(); editorInput.value = currentText; updatePreview(); editorModal.classList.add("active"); editorInput.focus(); } function closeModal() { if (editorModal) { editorModal.classList.remove("active"); } } function updatePreview() { if (!md || !editorInput || !markdownPreview) return; const content = editorInput.value; markdownPreview.innerHTML = md.render(content); } function applyChanges() { if (!mainChatInput || !editorInput) return; const newText = editorInput.value; mainChatInput.innerText = newText; const placeholderP = mainChatInput.querySelector("p.is-empty"); if (newText.trim() === "") { if (!placeholderP) { } } else { if (placeholderP) { } mainChatInput.classList.remove("is-editor-empty"); const parentPlaceholder = mainChatInput.querySelector("p.is-empty"); if (parentPlaceholder) parentPlaceholder.classList.remove("is-empty"); } mainChatInput.dispatchEvent( new Event("input", { bubbles: true, cancelable: true }) ); closeModal(); mainChatInput.focus(); } function injectEditorButton() { if (document.getElementById(EDITOR_BUTTON_ID)) { return; } mainChatInput = document.querySelector(CHAT_INPUT_SELECTOR); const voiceButton = document.querySelector(VOICE_BUTTON_SELECTOR); if (!mainChatInput || !voiceButton) { return; } const voiceButtonContainer = voiceButton.closest(".flex"); if (!voiceButtonContainer || !voiceButtonContainer.parentElement) { console.warn("Could not find suitable container for Markdown button."); return; } const editButton = document.createElement("button"); editButton.id = EDITOR_BUTTON_ID; editButton.className = "markdown-edit-btn"; editButton.type = "button"; editButton.title = "Markdown 编辑 (打开/关闭)"; editButton.innerHTML = ``; editButton.addEventListener("click", (e) => { e.preventDefault(); if (editorModal && editorModal.classList.contains("active")) { closeModal(); } else { openModal(); } }); voiceButtonContainer.parentElement.insertBefore( editButton, voiceButtonContainer ); console.log("Markdown Editor button injected."); } function handleKeyDown(e) { if (editorModal && editorModal.classList.contains("active")) { if (e.key === "Escape") { e.preventDefault(); closeModal(); } if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); applyChanges(); } } } ensureDependencies() .then(() => { injectEditorButton(); const observer = new MutationObserver((mutationsList, observer) => { if ( document.querySelector(CHAT_INPUT_SELECTOR) && !document.getElementById(EDITOR_BUTTON_ID) ) { injectEditorButton(); } }); observer.observe(document.body, { childList: true, subtree: true }); document.addEventListener("keydown", handleKeyDown); console.log("Markdown Editor script initialized and observing DOM."); }) .catch((error) => { console.error("Initialization failed:", error); }); })();