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();