您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为ChatGPT添加代码实时预览功能,支持多种编程语言的实时渲染,提供类似Claude的代码预览体验
当前为
/* ==UserStyle== */ @name ChatGPT实时渲染(MaynorAI) @namespace github.com/maynor/chatgpt-preview @version 1.3.0 @description 为ChatGPT添加代码实时预览功能,支持多种编程语言的实时渲染,提供类似Claude的代码预览体验 @author Maynor @preprocessor default @var checkbox enablePreview "Enable Preview" 1 @var select previewStyle "Preview Style" { "default": "Default", "minimal": "Minimal", "full": "Full Width" } @license GPL-2.0-only @homepageURL https://github.com/maynor/chatgpt-preview @supportURL https://github.com/maynor/chatgpt-preview/issues ==/UserStyle== */ @-moz-document domain("chat.openai.com"), domain("chatgpt.com"), domain("chatgpt-plus.top"), domain("maynor1024.live") { /* Your CSS code here */ } (function () { "use strict"; // 使用 MutationObserver 监听 DOM 变化 const observer = new MutationObserver(debounce(xuanranHTML, 500)); const createIframeObserver = new MutationObserver( debounce(createIframe, 500) ); // 观察目标节点的变化 observer.observe(document.body, { childList: true, subtree: true }); createIframeObserver.observe(document.body, { childList: true, subtree: true, }); // 首次调用渲染 window.addEventListener("load", () => { setTimeout(xuanranHTML, 1000); // 创建一个iframe setTimeout(createIframe, 1000); }); })(); function createIframe() { // 判断是否已经创建 dynamicContentIframe if (document.getElementById("dynamicContentIframe")) { console.log("已经创建 dynamicContentIframe"); return; } // 创建一个基于main标签的兄弟iframe元素 const mainElement = document.querySelector("main"); // mainElement.style.display = "flex"; mainElement.style.overflow = "hidden"; if (mainElement) { const iframe = document.createElement("iframe"); iframe.id = "dynamicContentIframe"; // 添加id以便动态修改内容 iframe.style.display = "relative"; iframe.style.width = "100%"; iframe.style.height = "100%"; iframe.style.backgroundColor = "#FFFDF6"; // 添加奶白色背景 // sandbox="allow-scripts" iframe.sandbox = "allow-scripts"; iframe.srcdoc = "<html><body></body></html>"; // 创建切换显示代码块的div const toggleCodeButton = document.createElement("div"); toggleCodeButton.id = "toggleCodeButton"; toggleCodeButton.style.position = "absolute"; toggleCodeButton.style.top = "10px"; toggleCodeButton.style.right = "40px"; toggleCodeButton.style.cursor = "pointer"; toggleCodeButton.innerHTML = ` <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M4 6H16M4 10H16M4 14H16" stroke="black" stroke-width="2" stroke-linecap="round"/> </svg> `; toggleCodeButton.onclick = () => { // document.getElementById("dynamicContentIframe").contentWindow.document.body.innerHTML = "123"; document.getElementById("codeContainer").style.display = document.getElementById("codeContainer").style.display === "none" ? "block" : "none"; }; // 创建缩小按钮 const minimizeButton = document.createElement("div"); minimizeButton.id = "minimizeButton"; minimizeButton.style.position = "absolute"; minimizeButton.style.top = "10px"; minimizeButton.style.right = "10px"; minimizeButton.style.cursor = "pointer"; minimizeButton.innerHTML = ` <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M4 10H16" stroke="black" stroke-width="2" stroke-linecap="round"/> </svg> `; minimizeButton.onclick = () => { iframe.style.display = iframe.style.display === "none" ? "block" : "none"; document.querySelector("main").style.display = document.querySelector("main").style.display === "block" ? "flex" : "block"; document .querySelector( "body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0 > div > div > div > nav > div.flex.justify-between.flex.h-\\[60px\\].items-center.md\\:h-header-height > span > button" ) .click(); }; // toggleCodeButton 和 minimizeButton 添加到一个div下 const buttonContainer = document.createElement("div"); buttonContainer.id = "buttonContainer"; buttonContainer.style.position = "relative"; buttonContainer.style.top = "10px"; buttonContainer.style.right = "10px"; buttonContainer.appendChild(minimizeButton); buttonContainer.appendChild(toggleCodeButton); // 直接将 iframe 和按钮添加到 main 元素下 mainElement.appendChild(iframe); mainElement.appendChild(buttonContainer); // 设置 main 元素为相对定位,以便正确定位最小化按钮 mainElement.style.position = "relative"; // mainElement.insertBefore(container, mainElement.nextSibling); // 创建一个用户存放显示代码的div const codeContainer = document.createElement("div"); codeContainer.id = "codeContainer"; codeContainer.style.width = "100%"; codeContainer.style.height = "100%"; codeContainer.style.zIndex = "1000"; // codeContainer.style.backgroundColor = "#FFFDF6"; // 添加奶白色背景 codeContainer.style.display = "block"; codeContainer.style.overflow = "hidden"; codeContainer.style.overflowY = "scroll"; codeContainer.style.display = "none"; mainElement.appendChild(codeContainer); } else { console.error("Main element not found"); } // 显示 document.getElementById("dynamicContentIframe").style.display = "block"; } function xuanranHTML() { const codes = document.querySelectorAll(".overflow-y-auto.p-4 code"); codes.forEach((codeElement) => { if (codeElement.classList.contains("processed")) { return; } codeElement.classList.add("processed"); // 获取代码块类型 const codeType = codeElement.parentNode.parentNode.children[0].innerText.toLowerCase(); // 检查代码内容是否包含 SVG 标签 const isSVGContent = codeElement.textContent.trim().startsWith('<svg'); // 根据不同类型进行渲染 switch(codeType) { case 'html': codeElement.parentNode.parentNode.style.display = "none"; renderSmallWindow(codeElement); break; case 'svg': case 'xml': // 添加对 xml 类型的支持 if (isSVGContent) { // 确认内容是 SVG renderSVG(codeElement); } else { console.log("不渲染: 非SVG的XML内容"); } break; case 'mermaid': renderMermaid(codeElement); break; case 'pptx': renderPPTX(codeElement); break; default: console.log("不渲染: " + codeType); } }); } function renderSmallWindow(codeElement) { // 创建组件容器 const componentContainer = document.createElement("div"); componentContainer.style.display = "flex"; componentContainer.style.alignItems = "center"; componentContainer.style.border = "1px solid #e5e7eb"; componentContainer.style.borderRadius = "8px"; componentContainer.style.padding = "10px"; componentContainer.style.backgroundColor = "#f9fafb"; componentContainer.style.marginBottom = "20px"; componentContainer.style.cursor = "pointer"; // 创建图标容器 const iconContainer = document.createElement("div"); iconContainer.style.borderRight = "1px solid #e5e7eb"; iconContainer.style.paddingRight = "10px"; // 创建 SVG 图标 const svgIcon = document.createElementNS( "http://www.w3.org/2000/svg", "svg" ); svgIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgIcon.setAttribute("style", "height: 24px; width: 24px; color: #6b7280;"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "0 0 24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "2"); const pathElement = document.createElementNS( "http://www.w3.org/2000/svg", "path" ); pathElement.setAttribute("stroke-linecap", "round"); pathElement.setAttribute("stroke-linejoin", "round"); pathElement.setAttribute( "d", "M16 8c0-1.104-.9-2-2-2H6c-1.1 0-2 .896-2 2v8c0 1.104.9 2 2 2h8c1.1 0 2-.896 2-2V8zm-4 4h.01m-3 0h.01M7 12h.01m0 0h.01M12 7v.01M8 7v.01M7 7v.01M12 8v.01m-5 0v.01m-1 0v.01" ); svgIcon.appendChild(pathElement); iconContainer.appendChild(svgIcon); // 创建文本容器 const textContainer = document.createElement("div"); textContainer.style.marginLeft = "10px"; // 创建标题 const title = document.createElement("h3"); title.textContent = codeElement.parentNode.parentNode.children[0].innerText; title.style.margin = "0"; title.style.fontSize = "16px"; title.style.fontWeight = "600"; title.style.color = "#374151"; // 创建描述 const description = document.createElement("p"); description.textContent = "预览页面 / 刷新渲染"; description.style.margin = "0"; description.style.fontSize = "14px"; description.style.color = "#6b7280"; textContainer.appendChild(title); textContainer.appendChild(description); // 组装组件 componentContainer.appendChild(iconContainer); componentContainer.appendChild(textContainer); // 添加点击事件,切换代码显示状态 componentContainer.addEventListener("click", function () { const codeParent = codeElement.parentNode.parentNode; const mainElement = document.querySelector("main"); // codeParent.style.display = codeParent.style.display === 'none' ? 'block' : 'none'; // 隐藏展开左侧历史记录 if (mainElement.style.display != "flex") { mainElement.style.display = "flex"; } if ( document.querySelector( "body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0" ).style.width != "0px" ) { document .querySelector( "body > div.relative.flex.h-full.w-full.overflow-hidden.transition-colors.z-0 > div.flex-shrink-0.overflow-x-hidden.bg-token-sidebar-surface-primary.max-md\\:\\!w-0 > div > div > div > nav > div.flex.justify-between.flex.h-\\[60px\\].items-center.md\\:h-header-height > span > button" ) .click(); // dynamicContentIframe document.getElementById("dynamicContentIframe").style.display = "block"; } // iframe 赋值 renderIframeContent( document.getElementById("dynamicContentIframe"), codeElement.textContent ); // 拦截script标签 // 设置代码容器代码 // document.getElementById("codeContainer").innerHTML = codeElement.parentNode.parentNode.innerHTML; const codeContainer = document.getElementById("codeContainer"); codeContainer.innerHTML = ""; const clonedContent = codeElement.parentNode.parentNode.cloneNode(true); codeContainer.appendChild(clonedContent); codeContainer.childNodes[0].style.display = "contents"; // 查找并处理按钮 const buttons = clonedContent.querySelectorAll("button"); buttons.forEach((button, index) => { console.log(button); if (button.className == "flex gap-1 items-center py-1") { button.addEventListener("click", function (event) { button.innerText = " success √ "; setTimeout(() => { button.innerText = "Copy code"; }, 1000); }); } button.addEventListener("click", function (event) { event.stopPropagation(); // 阻止事件冒泡到父元素 // 找到原始按钮并模拟点击 const originalButtons = codeElement.parentNode.parentNode.querySelectorAll( "button" ); if (originalButtons[index]) { originalButtons[index].click(); } }); }); // 添加事件委托到 codeContainer(用于处理代码元素的点击) codeContainer.addEventListener("click", function (event) { const clickedElement = event.target.closest("code"); if (clickedElement) { // 模拟原始代码元素的点击行为 const originalCodeElement = codeElement.closest("code"); if (originalCodeElement) { originalCodeElement.click(); } } }); }); // 将组件插入到代码元素之前 codeElement.parentNode.parentNode.insertAdjacentElement( "beforebegin", componentContainer ); return componentContainer; } function renderIframeContent(iframe, content) { // console.log(__remixContext.state.loaderData.root.cspScriptNonce); // Add nonce to script tags in content const nonce = __remixContext.state.loaderData.root.cspScriptNonce; content = content.replace(/<script/g, `<script nonce="${nonce}"`); iframe.srcdoc = content; return; // 获取 iframe 内部的 document 对象 const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; // 将 code ��的内容设置为 iframe 的内容 iframeDoc.open(); if (true) { // 刷新特效,true为有感刷新,!true为无痕刷新 // iframeDoc.write(`loading`); // 生成一个随机的nonce值 const nonce = generateNonce(); // 在content中添加nonce // content = content.replace(/<script/g, `<script nonce="${nonce}"`); // 设置meta头替换 // content = content.replace(/<meta/g, `<meta nonce="${nonce}"`); // let doms = new DOMParser().parseFromString(content, "text/html"); // Remove script tags from content // content = content.replace( // /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, // "" // ); // 插入 iframeDoc.write(content); doms.querySelectorAll("script").forEach((script) => { return; console.log("script"); const newScript = iframeDoc.createElement("script"); newScript.textContent = script.textContent; newScript.nonce = nonce; // iframeDoc.documentElement.appendChild(newScript); // 创建一个blob URL来加载脚本 const blob = new Blob([script.textContent], { type: "application/javascript", }); const scriptUrl = URL.createObjectURL(blob); newScript.src = scriptUrl; script.onload = () => { console.log("加载完成"); URL.revokeObjectURL(scriptUrl); }; iframeDoc.documentElement.appendChild(newScript); }); // setTimeout(() => iframeDoc.write(content), 100); } else { iframeDoc.write(content); } iframeDoc.close(); } function debounce(func, wait) { let timeout; return function () { const context = this, args = arguments; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } function generateNonce() { return ( Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) ); } // 添加新的渲染函数 function renderSVG(codeElement) { // 创建组件容器 const componentContainer = document.createElement("div"); componentContainer.style.display = "flex"; componentContainer.style.alignItems = "center"; componentContainer.style.border = "1px solid #e5e7eb"; componentContainer.style.borderRadius = "8px"; componentContainer.style.padding = "10px"; componentContainer.style.backgroundColor = "#f9fafb"; componentContainer.style.marginBottom = "20px"; componentContainer.style.cursor = "pointer"; // 创建图标容器 const iconContainer = document.createElement("div"); iconContainer.style.borderRight = "1px solid #e5e7eb"; iconContainer.style.paddingRight = "10px"; // 创建 SVG 图标 const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgIcon.setAttribute("style", "height: 24px; width: 24px; color: #6b7280;"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "0 0 24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "2"); const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); pathElement.setAttribute("stroke-linecap", "round"); pathElement.setAttribute("stroke-linejoin", "round"); pathElement.setAttribute("d", "M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2zm0 0V5"); svgIcon.appendChild(pathElement); iconContainer.appendChild(svgIcon); // 创建文本容器 const textContainer = document.createElement("div"); textContainer.style.marginLeft = "10px"; // 创建标题 const title = document.createElement("h3"); title.textContent = "SVG Preview"; title.style.margin = "0"; title.style.fontSize = "16px"; title.style.fontWeight = "600"; title.style.color = "#374151"; // 创建描述 const description = document.createElement("p"); description.textContent = "点击切换显示/隐藏"; description.style.margin = "0"; description.style.fontSize = "14px"; description.style.color = "#6b7280"; textContainer.appendChild(title); textContainer.appendChild(description); // 组装组件 componentContainer.appendChild(iconContainer); componentContainer.appendChild(textContainer); // 创建 SVG 预览容器 const svgPreviewContainer = document.createElement("div"); svgPreviewContainer.style.margin = "10px 0"; svgPreviewContainer.style.padding = "20px"; svgPreviewContainer.style.backgroundColor = "#fff"; svgPreviewContainer.style.border = "1px solid #e5e7eb"; svgPreviewContainer.style.borderRadius = "8px"; svgPreviewContainer.style.display = "none"; svgPreviewContainer.innerHTML = codeElement.textContent; // 创建代码容器 const codeContainer = document.createElement("div"); codeContainer.style.margin = "10px 0"; codeContainer.style.display = "none"; const clonedContent = codeElement.parentNode.parentNode.cloneNode(true); codeContainer.appendChild(clonedContent); codeContainer.childNodes[0].style.display = "block"; // 添加点击事件 componentContainer.addEventListener("click", function() { svgPreviewContainer.style.display = svgPreviewContainer.style.display === "none" ? "block" : "none"; codeContainer.style.display = codeContainer.style.display === "none" ? "block" : "none"; }); // 将组件插入到代码元素的位置 const parent = codeElement.parentNode.parentNode; parent.style.display = "none"; parent.insertAdjacentElement("beforebegin", componentContainer); componentContainer.insertAdjacentElement("afterend", svgPreviewContainer); svgPreviewContainer.insertAdjacentElement("afterend", codeContainer); return componentContainer; } function renderMermaid(codeElement) { // 创建组件容器 const componentContainer = document.createElement("div"); componentContainer.style.display = "flex"; componentContainer.style.alignItems = "center"; componentContainer.style.border = "1px solid #e5e7eb"; componentContainer.style.borderRadius = "8px"; componentContainer.style.padding = "10px"; componentContainer.style.backgroundColor = "#f9fafb"; componentContainer.style.marginBottom = "20px"; componentContainer.style.cursor = "pointer"; // 创建图标容器 const iconContainer = document.createElement("div"); iconContainer.style.borderRight = "1px solid #e5e7eb"; iconContainer.style.paddingRight = "10px"; // 创建 SVG 图标 const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgIcon.setAttribute("style", "height: 24px; width: 24px; color: #6b7280;"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "0 0 24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "2"); const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); pathElement.setAttribute("stroke-linecap", "round"); pathElement.setAttribute("stroke-linejoin", "round"); pathElement.setAttribute("d", "M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"); svgIcon.appendChild(pathElement); iconContainer.appendChild(svgIcon); // 创建文本容器 const textContainer = document.createElement("div"); textContainer.style.marginLeft = "10px"; // 创建标题 const title = document.createElement("h3"); title.textContent = "Mermaid Diagram"; title.style.margin = "0"; title.style.fontSize = "16px"; title.style.fontWeight = "600"; title.style.color = "#374151"; // 创建描述 const description = document.createElement("p"); description.textContent = "点击切换显示/隐藏"; description.style.margin = "0"; description.style.fontSize = "14px"; description.style.color = "#6b7280"; textContainer.appendChild(title); textContainer.appendChild(description); // 组装组件 componentContainer.appendChild(iconContainer); componentContainer.appendChild(textContainer); // 创建 Mermaid 预览容器 const mermaidPreviewContainer = document.createElement("div"); mermaidPreviewContainer.style.margin = "10px 0"; mermaidPreviewContainer.style.padding = "20px"; mermaidPreviewContainer.style.backgroundColor = "#fff"; mermaidPreviewContainer.style.border = "1px solid #e5e7eb"; mermaidPreviewContainer.style.borderRadius = "8px"; mermaidPreviewContainer.style.display = "none"; // 创建 Mermaid 图表容器 const mermaidContainer = document.createElement("div"); mermaidContainer.className = "mermaid"; mermaidContainer.textContent = codeElement.textContent; mermaidPreviewContainer.appendChild(mermaidContainer); // 创建代码容器 const codeContainer = document.createElement("div"); codeContainer.style.margin = "10px 0"; codeContainer.style.display = "none"; const clonedContent = codeElement.parentNode.parentNode.cloneNode(true); codeContainer.appendChild(clonedContent); codeContainer.childNodes[0].style.display = "block"; // 添加点击事件 componentContainer.addEventListener("click", function() { const newDisplayState = mermaidPreviewContainer.style.display === "none" ? "block" : "none"; mermaidPreviewContainer.style.display = newDisplayState; codeContainer.style.display = newDisplayState; // 如果是显示状态,确保 Mermaid 图表被渲染 if (newDisplayState === "block") { if (typeof mermaid === 'undefined') { // 动态加载 mermaid const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'; script.onload = () => { mermaid.initialize({ startOnLoad: true }); mermaid.init(undefined, mermaidContainer); }; document.head.appendChild(script); } else { mermaid.init(undefined, mermaidContainer); } } }); // 将组件插入到代码元素的位置 const parent = codeElement.parentNode.parentNode; parent.style.display = "none"; parent.insertAdjacentElement("beforebegin", componentContainer); componentContainer.insertAdjacentElement("afterend", mermaidPreviewContainer); mermaidPreviewContainer.insertAdjacentElement("afterend", codeContainer); return componentContainer; } // 新增 PPTX 渲染函数 function renderPPTX(codeElement) { // 创建组件容器 const componentContainer = document.createElement("div"); componentContainer.style.display = "flex"; componentContainer.style.alignItems = "center"; componentContainer.style.border = "1px solid #e5e7eb"; componentContainer.style.borderRadius = "8px"; componentContainer.style.padding = "10px"; componentContainer.style.backgroundColor = "#f9fafb"; componentContainer.style.marginBottom = "20px"; componentContainer.style.cursor = "pointer"; // 创建图标容器 const iconContainer = document.createElement("div"); iconContainer.style.borderRight = "1px solid #e5e7eb"; iconContainer.style.paddingRight = "10px"; // 创建 PPT 图标 const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); svgIcon.setAttribute("style", "height: 24px; width: 24px; color: #6b7280;"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "0 0 24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "2"); const pathElement = document.createElementNS("http://www.w3.org/2000/svg", "path"); pathElement.setAttribute("stroke-linecap", "round"); pathElement.setAttribute("stroke-linejoin", "round"); pathElement.setAttribute("d", "M4 5h16a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1zm8 3v8m-4-4h8"); svgIcon.appendChild(pathElement); iconContainer.appendChild(svgIcon); // 创建文本容器 const textContainer = document.createElement("div"); textContainer.style.marginLeft = "10px"; // 创建标题 const title = document.createElement("h3"); title.textContent = "PowerPoint Presentation"; title.style.margin = "0"; title.style.fontSize = "16px"; title.style.fontWeight = "600"; title.style.color = "#374151"; // 创建描述 const description = document.createElement("p"); description.textContent = "点击切换显示/隐藏"; description.style.margin = "0"; description.style.fontSize = "14px"; description.style.color = "#6b7280"; textContainer.appendChild(title); textContainer.appendChild(description); // 组装组件 componentContainer.appendChild(iconContainer); componentContainer.appendChild(textContainer); // 创建 PPTX 预览容器 const pptxPreviewContainer = document.createElement("div"); pptxPreviewContainer.style.margin = "10px 0"; pptxPreviewContainer.style.padding = "20px"; pptxPreviewContainer.style.backgroundColor = "#fff"; pptxPreviewContainer.style.border = "1px solid #e5e7eb"; pptxPreviewContainer.style.borderRadius = "8px"; pptxPreviewContainer.style.display = "none"; // 创��� PPTX 容器 const pptxContainer = document.createElement("div"); pptxContainer.id = "pptx-container-" + Math.random().toString(36).substr(2, 9); pptxPreviewContainer.appendChild(pptxContainer); // 创建控制按钮 const controlsContainer = document.createElement("div"); controlsContainer.style.marginTop = "10px"; controlsContainer.style.textAlign = "center"; const prevButton = document.createElement("button"); prevButton.textContent = "上一页"; prevButton.style.marginRight = "10px"; prevButton.style.padding = "5px 10px"; const nextButton = document.createElement("button"); nextButton.textContent = "下一页"; nextButton.style.padding = "5px 10px"; controlsContainer.appendChild(prevButton); controlsContainer.appendChild(nextButton); pptxPreviewContainer.appendChild(controlsContainer); // 创建代码容器 const codeContainer = document.createElement("div"); codeContainer.style.margin = "10px 0"; codeContainer.style.display = "none"; const clonedContent = codeElement.parentNode.parentNode.cloneNode(true); codeContainer.appendChild(clonedContent); codeContainer.childNodes[0].style.display = "block"; // 添加点击事件 componentContainer.addEventListener("click", function() { const newDisplayState = pptxPreviewContainer.style.display === "none" ? "block" : "none"; pptxPreviewContainer.style.display = newDisplayState; codeContainer.style.display = newDisplayState; if (newDisplayState === "block") { // 检查是否已加载 pptxjs if (typeof jQuery === 'undefined') { // 加载 jQuery const jqueryScript = document.createElement('script'); jqueryScript.src = 'https://code.jquery.com/jquery-3.6.0.min.js'; jqueryScript.onload = () => { // 加载 pptxjs const pptxjsScript = document.createElement('script'); pptxjsScript.src = 'https://cdn.jsdelivr.net/gh/meshesha/pptxjs@latest/dist/pptxjs.min.js'; pptxjsScript.onload = () => { renderPPTXContent(pptxContainer.id, codeElement.textContent); }; document.head.appendChild(pptxjsScript); // 加载 pptxjs CSS const pptxjsCSS = document.createElement('link'); pptxjsCSS.rel = 'stylesheet'; pptxjsCSS.href = 'https://cdn.jsdelivr.net/gh/meshesha/pptxjs@latest/dist/pptxjs.min.css'; document.head.appendChild(pptxjsCSS); }; document.head.appendChild(jqueryScript); } else { renderPPTXContent(pptxContainer.id, codeElement.textContent); } } }); // 将组件插入到代码元素的位置 const parent = codeElement.parentNode.parentNode; parent.style.display = "none"; parent.insertAdjacentElement("beforebegin", componentContainer); componentContainer.insertAdjacentElement("afterend", pptxPreviewContainer); pptxPreviewContainer.insertAdjacentElement("afterend", codeContainer); return componentContainer; } // 渲染 PPTX 内容的辅助函数 function renderPPTXContent(containerId, base64Content) { try { // 将 base64 转换为 Blob const byteCharacters = atob(base64Content); const byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' }); // 使用 pptxjs 渲染 $("#" + containerId).pptxToHtml({ pptxFileUrl: URL.createObjectURL(blob), slidesScale: "50%", slideMode: true, keyBoardShortCut: true }); } catch (error) { console.error("PPTX rendering failed:", error); document.getElementById(containerId).innerHTML = "无法渲染 PPTX 内容,请检查格式是否正确。"; } } function savaAiRecording(askFileName = false, format = 'html') { // askFileName为true时弹窗询问文件名 var fileName = document.title; var today = new Date(); var month = (today.getMonth() + 1).toString().padStart(2, '0'); var day = today.getDate().toString().padStart(2, '0'); fileName = `${fileName}-${month}${day}.${format}`; fileName = askFileName ? prompt('输入要保存的文件名:', fileName) : fileName; var body = document.createElement('body'); body.innerHTML = document.body.innerHTML; // 删除所有script标签 var ps = body.querySelectorAll('script'); for (var i = 0; i < ps.length; i++) { ps[i].parentNode.removeChild(ps[i]); } // 删除所有style标签,因为downloadHtml会自动再获取一次 var ps = body.querySelectorAll('style'); for (var i = 0; i < ps.length; i++) { ps[i].parentNode.removeChild(ps[i]); } // 删除下边框 var element = body.querySelector('#__next > div > div > main > div.absolute'); element && element.remove(); // 删除侧边框 var element = body.querySelector('#__next > div > div.hidden'); element && element.remove(); // 删除侧边框间隔 var element = body.querySelector('#__next > div > div'); if (element) { element.className = ''; } // 添加script标签,用于修复一键复制 var script = document.createElement('script'); script.innerHTML = copyScript; body.appendChild(script); if (format === 'html') { downloadHtml(body.innerHTML, fileName); } else if (format === 'docx') { // 使用 docx 库生成 docx 文件 var doc = new docx.Document(); doc.addSection({ children: [ new docx.Paragraph(body.innerText) ] }); docx.Packer.toBlob(doc).then(blob => { saveAs(blob, fileName); }); } else if (format === 'md') { // 使用 showdown 库将 HTML 转换为 Markdown var converter = new showdown.Converter(); var markdown = converter.makeMarkdown(body.innerHTML); var blob = new Blob([markdown], { type: 'text/markdown' }); saveAs(blob, fileName); } }