editor.js (4.3 KB)
1 import { saveToStorage } from './storage.js'; 2 import { saveFile, loadFile } from './file-operations.js'; 3 import { updatePreview, setupPreviewPane } from './preview-manager.js'; 4 import { navigateSpread, toggleFullscreen, initializeSpreadNav, getIsFullscreen } from './spread-navigation.js'; 5 import { initializeCodeMirror, closeFontPicker } from './codemirror-config.js'; 6 import { preloadAllFonts } from './font-registry.js'; 7 import { isMobileDevice, exitMobileKeyboardMode, initializeMobileKeyboard } from './mobile-keyboard.js'; 8 9 // Global state 10 let editorView; 11 let isEditorFocused = false; 12 13 // Wrapper functions for updatePreview 14 function updatePreviewWrapper() { 15 updatePreview(editorView, isEditorFocused); 16 } 17 18 function updatePreviewFromContent() { 19 updatePreviewWrapper(); 20 } 21 22 // Message handler for iframe communication 23 window.addEventListener('message', function(event) { 24 if (event.data === 'toggleFullscreen') { 25 toggleFullscreen(); 26 updatePreviewWrapper(); 27 } else if (event.data === 'prevSpread') { 28 navigateSpread(-1, updatePreviewWrapper); 29 } else if (event.data === 'nextSpread') { 30 navigateSpread(1, updatePreviewWrapper); 31 } else if (event.data === 'saveFile') { 32 window.saveFile(); 33 } else if (event.data?.type === 'scaleChange') { 34 // Update background grid size and position to match zine preview 35 const previewPane = document.querySelector('.preview-pane'); 36 const preview = document.querySelector('#preview'); 37 if (previewPane && preview) { 38 // Get iframe position relative to preview pane 39 const iframeRect = preview.getBoundingClientRect(); 40 const paneRect = previewPane.getBoundingClientRect(); 41 const iframeOffsetX = iframeRect.left - paneRect.left; 42 const iframeOffsetY = iframeRect.top - paneRect.top; 43 44 // Spread position in pane coordinates 45 const spreadLeft = iframeOffsetX + event.data.spreadLeft; 46 const spreadTop = iframeOffsetY + event.data.spreadTop; 47 48 previewPane.style.setProperty('--grid-width', `${event.data.gridWidth}px`); 49 previewPane.style.setProperty('--grid-height', `${event.data.gridHeight}px`); 50 previewPane.style.setProperty('--spread-left', `${spreadLeft}px`); 51 previewPane.style.setProperty('--spread-top', `${spreadTop}px`); 52 previewPane.classList.add('grid-ready'); 53 } 54 } 55 }); 56 57 // Expose file operations to window for keyboard shortcuts 58 window.saveFile = function() { 59 saveFile(() => editorView.state.doc.toString()); 60 }; 61 62 window.loadFile = function() { 63 loadFile(editorView, updatePreviewWrapper); 64 }; 65 66 // Initialize editor 67 async function initializeEditor() { 68 editorView = await initializeCodeMirror(saveToStorage, updatePreviewFromContent); 69 70 // Initialize spread navigation 71 initializeSpreadNav((delta) => navigateSpread(delta, updatePreviewWrapper)); 72 73 // Setup preview pane 74 setupPreviewPane(updatePreviewWrapper); 75 76 // Initial preview 77 updatePreviewWrapper(); 78 79 // Track editor focus 80 editorView.contentDOM.addEventListener('focus', () => { isEditorFocused = true; }); 81 editorView.contentDOM.addEventListener('blur', () => { 82 isEditorFocused = false; 83 closeFontPicker(); 84 if (isMobileDevice()) { 85 exitMobileKeyboardMode(editorView, updatePreviewWrapper); 86 } 87 }); 88 89 editorView.focus(); 90 91 // Keyboard shortcuts (only when editor not focused, since CodeMirror handles its own) 92 document.addEventListener('keydown', function(e) { 93 const {closeSearchPanel, openSearchPanel} = window.CodeMirror; 94 95 if ((e.metaKey || e.ctrlKey) && e.key === 'f') { 96 e.preventDefault(); 97 closeSearchPanel(editorView) || openSearchPanel(editorView); 98 } 99 // Print the iframe content instead of the parent page 100 if ((e.metaKey || e.ctrlKey) && e.key === 'p') { 101 e.preventDefault(); 102 try { 103 document.getElementById('preview').contentWindow.print(); 104 } catch (err) { 105 window.print(); 106 } 107 } 108 }); 109 110 // Initialize mobile keyboard handling 111 initializeMobileKeyboard( 112 () => isEditorFocused, 113 () => exitMobileKeyboardMode(editorView, updatePreviewWrapper) 114 ); 115 116 // Exit fullscreen when viewport is too short (matches CSS @media max-height: 200px) 117 window.addEventListener('resize', function() { 118 if (getIsFullscreen() && window.innerHeight <= 270) { 119 toggleFullscreen(); 120 updatePreviewWrapper(); 121 } 122 }); 123 } 124 125 // Initialize 126 initializeEditor(); 127 128 // Preload fonts in the background so they're ready when needed 129 preloadAllFonts();