commit 3955882d972ab211c82e5d1067ff4436f5ad377b
parent 8f6f6255f27cb5902bd775039fcaeaa6e8e0e015
Author: Hunter
Date: Thu, 24 Jul 2025 15:29:45 -0400
create fresh JS execution context on each render
Diffstat:
| M | index.html | | | 144 | ++++++++++++++++++++++++++++++------------------------------------------------- |
1 file changed, 54 insertions(+), 90 deletions(-)
diff --git a/index.html b/index.html
@@ -182,36 +182,12 @@
}
- function createFullscreenToggle() {
- try {
- if (!preview.contentDocument) return;
-
- const doc = preview.contentDocument;
-
- // Remove existing button if it exists
- const existingButton = doc.getElementById('fullscreenToggle');
- if (existingButton) {
- existingButton.remove();
- }
-
- // Create button element
- const button = doc.createElement('button');
- button.id = 'fullscreenToggle';
- button.className = 'iframe-fullscreen-toggle';
- button.title = 'Toggle fullscreen';
- button.innerHTML = `<img src="resources/fullscreen.svg" width="20" height="20" alt="Fullscreen">`;
-
- // Add click handler
- button.addEventListener('click', toggleFullscreen);
-
- // Append to body
- if (doc.body) {
- doc.body.appendChild(button);
- }
- } catch (e) {
- // Ignore cross-origin errors
+ // Listen for messages from iframe
+ window.addEventListener('message', function(event) {
+ if (event.data === 'toggleFullscreen') {
+ toggleFullscreen();
}
- }
+ });
function updatePreview() {
const code = editorView.state.doc.toString();
@@ -227,73 +203,61 @@
// Ignore cross-origin errors
}
- // Write HTML directly to iframe document
- const doc = preview.contentDocument || preview.contentWindow.document;
- doc.open();
-
- // Ensure we have a proper HTML document structure for the button
- const htmlContent = code.trim() || '<!DOCTYPE html><html><head></head><body></body></html>';
- doc.write(htmlContent);
+ // Use srcdoc to create a completely fresh document context
+ preview.srcdoc = code.trim() || '<!DOCTYPE html><html><head></head><body></body></html>';
- // Inject CSS to disable overscroll and add fullscreen toggle styles
- const style = doc.createElement('style');
- style.textContent = `
- * { overscroll-behavior: none !important; }
-
- .iframe-fullscreen-toggle {
- position: fixed;
- top: 5px;
- right: 5px;
- z-index: 10000;
- background: rgba(0, 0, 0, 0.2);
- color: white;
- border: none;
- border-radius: 4px;
- width: 32px;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- transition: background-color 0.2s;
- box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
- }
-
- .iframe-fullscreen-toggle img {
- filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3));
- opacity: 0.8;
- transition: opacity 0.2s;
- }
-
- @media (hover: hover) and (pointer: fine) {
- .iframe-fullscreen-toggle:hover {
- background: rgba(0, 0, 0, 0.35);
- }
-
- .iframe-fullscreen-toggle:hover img {
- opacity: 1;
- }
- }
- `;
- if (doc.head) {
- doc.head.appendChild(style);
- }
-
- // Create fullscreen toggle button immediately
- createFullscreenToggle();
-
- doc.close();
-
- // Restore scroll position after a short delay to ensure content is rendered
- setTimeout(() => {
+ // Add our functionality after the iframe loads
+ const onLoad = () => {
try {
- if (preview.contentWindow) {
- preview.contentWindow.scrollTo(scrollX, scrollY);
+ const doc = preview.contentDocument;
+ if (!doc) return;
+
+ // Add CSS for overscroll and button
+ const style = doc.createElement('style');
+ style.textContent = '* { overscroll-behavior: none !important; } .iframe-fullscreen-toggle { position: fixed; top: 5px; right: 5px; z-index: 10000; background: rgba(0, 0, 0, 0.2); color: white; border: none; border-radius: 4px; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background-color 0.2s; box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); } .iframe-fullscreen-toggle img { filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3)); opacity: 0.8; transition: opacity 0.2s; } @media (hover: hover) and (pointer: fine) { .iframe-fullscreen-toggle:hover { background: rgba(0, 0, 0, 0.35); } .iframe-fullscreen-toggle:hover img { opacity: 1; } }';
+ doc.head.appendChild(style);
+
+ // Create fullscreen button
+ const existingButton = doc.getElementById('fullscreenToggle');
+ if (existingButton) existingButton.remove();
+
+ const button = doc.createElement('button');
+ button.id = 'fullscreenToggle';
+ button.className = 'iframe-fullscreen-toggle';
+ button.title = 'Toggle fullscreen';
+
+ const img = doc.createElement('img');
+ img.src = 'resources/fullscreen.svg';
+ img.width = 20;
+ img.height = 20;
+ img.alt = 'Fullscreen';
+ button.appendChild(img);
+
+ button.addEventListener('click', function() {
+ parent.postMessage('toggleFullscreen', '*');
+ });
+
+ if (doc.body) {
+ doc.body.appendChild(button);
}
+
+ // Restore scroll position
+ setTimeout(() => {
+ try {
+ if (preview.contentWindow) {
+ preview.contentWindow.scrollTo(scrollX, scrollY);
+ }
+ } catch (e) {
+ // Ignore cross-origin errors
+ }
+ }, 10);
} catch (e) {
// Ignore cross-origin errors
}
- }, 10);
+
+ preview.removeEventListener('load', onLoad);
+ };
+ preview.addEventListener('load', onLoad);
}
function saveToStorage() {