Last active
September 19, 2024 13:26
-
-
Save CurtisAccelerate/64a20b1d5df6240119bb0a3f4b5abf31 to your computer and use it in GitHub Desktop.
ChatGPT_Codeblock_Processor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The following is a TamperMonkey script that adds a run eleement to code blocks for HTML content. | |
- Now works without manual reloading! | |
- Now works with Javascript. Must disable CSP policy. Disable at own risk. | |
- Removed the run demo from the frame area | |
https://chromewebstore.google.com/detail/csp-unblock/lkbelpgpclajeekijigjffllhigbhobd?hl=en | |
// ==UserScript== | |
// @name ChatGPT Code Block Processor 200 | |
// @namespace http://tampermonkey.net/ | |
// @version 2.0.1 | |
// @description Add "Run Demo" button as a hover action on code blocks in ChatGPT responses with draggable panel. | |
// @match https://chatgpt.com/* | |
// @grant GM_addElement | |
// @grant GM_addStyle | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
let panel; | |
let isDragging = false; | |
let startX; | |
let startWidth; | |
function createSlideOutPanel(codeBlock) { | |
if (panel) { | |
panel.remove(); | |
} | |
panel = document.createElement('div'); | |
panel.style.cssText = ` | |
position: fixed; | |
top: 0; | |
right: 0; | |
width: 600px; | |
height: 100%; | |
background: #f7f7f8; | |
box-shadow: -2px 0 5px rgba(0,0,0,0.3); | |
z-index: 1000; | |
display: flex; | |
flex-direction: column; | |
transform: translateX(100%); | |
transition: transform 0.3s ease-in-out; | |
`; | |
const header = document.createElement('div'); | |
header.style.cssText = ` | |
padding: 10px; | |
background: #282c34; | |
color: #fff; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
cursor: move; | |
`; | |
const closeButton = document.createElement('button'); | |
closeButton.textContent = 'Close'; | |
closeButton.style.cssText = ` | |
background: #ff5f57; | |
border: none; | |
border-radius: 5px; | |
padding: 5px 10px; | |
cursor: pointer; | |
color: white; | |
`; | |
closeButton.onclick = () => panel.style.transform = 'translateX(100%)'; | |
header.appendChild(closeButton); | |
panel.appendChild(header); | |
const contentContainer = document.createElement('div'); | |
contentContainer.style.cssText = ` | |
padding: 10px; | |
overflow-y: auto; | |
flex-grow: 1; | |
`; | |
const iframe = document.createElement('iframe'); | |
iframe.style.cssText = ` | |
width: 100%; | |
height: 100%; | |
border: none; | |
margin: 0; | |
padding: 0; | |
`; | |
contentContainer.appendChild(iframe); | |
panel.appendChild(contentContainer); | |
document.body.appendChild(panel); | |
// Clone the code block and remove the "Run Demo" button | |
const cleanCodeBlock = codeBlock.cloneNode(true); | |
const runDemoButton = cleanCodeBlock.querySelector('.run-demo-hover-button'); | |
if (runDemoButton) { | |
runDemoButton.remove(); | |
} | |
const doc = iframe.contentDocument || iframe.contentWindow.document; | |
doc.open(); | |
doc.write(cleanCodeBlock.textContent); | |
doc.close(); | |
setTimeout(() => panel.style.transform = 'translateX(0)', 0); | |
header.addEventListener('mousedown', startDragging); | |
document.addEventListener('mousemove', drag); | |
document.addEventListener('mouseup', stopDragging); | |
document.addEventListener('click', function(event) { | |
if (!panel.contains(event.target) && !event.target.closest('.run-demo-hover-button')) { | |
panel.style.transform = 'translateX(100%)'; | |
} | |
}, { once: true }); | |
} | |
function startDragging(e) { | |
isDragging = true; | |
startX = e.clientX; | |
startWidth = parseInt(document.defaultView.getComputedStyle(panel).width, 10); | |
} | |
function drag(e) { | |
if (!isDragging) return; | |
const width = startWidth - (e.clientX - startX); | |
panel.style.width = `${width}px`; | |
} | |
function stopDragging() { | |
isDragging = false; | |
} | |
function addHoverButton(codeBlock) { | |
if (!codeBlock.querySelector('.run-demo-hover-button')) { | |
const hoverButton = document.createElement('button'); | |
hoverButton.textContent = 'Run Demo'; | |
hoverButton.className = 'run-demo-hover-button'; | |
hoverButton.style.cssText = ` | |
position: absolute; | |
top: 10px; | |
right: 10px; | |
padding: 5px 10px; | |
background-color: #4CAF50; | |
color: white; | |
border: none; | |
border-radius: 3px; | |
cursor: pointer; | |
display: none; | |
z-index: 1000; | |
`; | |
hoverButton.onclick = (e) => { | |
e.stopPropagation(); | |
createSlideOutPanel(codeBlock); | |
}; | |
codeBlock.style.position = 'relative'; | |
codeBlock.appendChild(hoverButton); | |
codeBlock.addEventListener('mouseenter', () => { | |
hoverButton.style.display = 'block'; | |
}); | |
codeBlock.addEventListener('mouseleave', () => { | |
hoverButton.style.display = 'none'; | |
}); | |
} | |
} | |
function processCodeBlocks() { | |
const codeBlocks = document.querySelectorAll('.overflow-y-auto'); | |
codeBlocks.forEach(codeBlock => { | |
if (codeBlock.closest('.markdown')) { | |
addHoverButton(codeBlock); | |
} | |
}); | |
} | |
function observeChat() { | |
const observer = new MutationObserver((mutations) => { | |
mutations.forEach((mutation) => { | |
if (mutation.type === 'childList') { | |
mutation.addedNodes.forEach((node) => { | |
if (node.nodeType === Node.ELEMENT_NODE) { | |
const codeBlocks = node.querySelectorAll('.overflow-y-auto'); | |
codeBlocks.forEach(codeBlock => { | |
if (codeBlock.closest('.markdown')) { | |
addHoverButton(codeBlock); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
}); | |
const chatContainer = document.querySelector('main'); | |
if (chatContainer) { | |
observer.observe(chatContainer, { childList: true, subtree: true }); | |
} | |
} | |
function addIndicator() { | |
const indicator = document.createElement('div'); | |
indicator.textContent = 'Code Block Processor Active'; | |
indicator.style.cssText = ` | |
position: fixed; | |
top: 10px; | |
right: 10px; | |
z-index: 1000; | |
padding: 5px 10px; | |
background-color: #4CAF50; | |
color: white; | |
border-radius: 5px; | |
font-size: 12px; | |
`; | |
document.body.appendChild(indicator); | |
setTimeout(() => indicator.style.display = 'none', 3000); | |
} | |
function initializeProcessor() { | |
addIndicator(); | |
processCodeBlocks(); | |
observeChat(); | |
} | |
// Use MutationObserver to wait for the chat interface to load | |
const bodyObserver = new MutationObserver((mutations) => { | |
if (document.querySelector('main')) { | |
bodyObserver.disconnect(); | |
initializeProcessor(); | |
} | |
}); | |
bodyObserver.observe(document.body, { childList: true, subtree: true }); | |
})(); |
MIT license. Free for use, commercial or in any license desired, however desired. No warranty. Attribution appreciated.
Thanks, amazing!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, quick question, what License is this under?