From c3057894287f839578ed7c413e67f3041ee80a48 Mon Sep 17 00:00:00 2001 From: Amit Haridas Date: Sun, 26 Oct 2025 14:36:05 +0530 Subject: [PATCH] FINAL FIX: Proper print preview and file loading with correct DOM timing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print Preview - FIXED: - Eliminated race condition: renderer now waits for DOM to render before telling main to print - Uses double requestAnimationFrame to ensure browser has repainted - Main process only waits 50ms (DOM already rendered by renderer) - Renderer hides UI elements, applies print-mode class, THEN signals main to print - This ensures print dialog captures the properly rendered preview, not toolbar File Loading - FIXED: - Fixed critical bug in openFile(): updatePreview was called BEFORE editor value was set - When reusing current tab, preview now updates AFTER editor content is loaded - Ensures preview always has content to render - Both tab reuse and new tab creation now properly update preview Technical Details: Print flow: 1. User clicks Print Preview 2. Menu sends 'print-preview' to renderer 3. Renderer: hide UI, set print-mode class 4. Renderer: requestAnimationFrame x2 (waits for repaints) 5. Renderer: sends 'do-print' to main (DOM fully rendered) 6. Main: small 50ms delay, then prints 7. Result: prints preview content, not toolbar! File loading flow: 1. User double-clicks .md file (or file association) 2. Main process stores file path 3. Renderer signals ready after theme loads 4. Main sends file-opened message 5. Renderer openFile() called 6. Editor value set 7. THEN updatePreview() called (content exists) 8. Preview renders correctly! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/main.js | 32 ++++++++---------- src/renderer.js | 88 ++++++++++++++++++++++++------------------------- 2 files changed, 58 insertions(+), 62 deletions(-) diff --git a/src/main.js b/src/main.js index 9ad7349..038543a 100644 --- a/src/main.js +++ b/src/main.js @@ -1166,37 +1166,33 @@ ipcMain.on('set-current-file', (event, filePath) => { currentFile = filePath; }); -// Handle print preview +// Handle print preview - send signal to renderer to prepare ipcMain.on('print-preview', (event) => { if (mainWindow) { - // Prepare for printing preview only (black text, no colors) - mainWindow.webContents.send('prepare-print-preview', false); - // Give renderer time to prepare, then print - setTimeout(() => { - mainWindow.webContents.print({ - silent: false, - printBackground: false, - color: true, - margin: { marginType: 'default' } - }); - }, 100); + mainWindow.webContents.send('print-preview'); } }); -// Handle print preview with styles +// Handle print preview with styles - send signal to renderer to prepare ipcMain.on('print-preview-styled', (event) => { if (mainWindow) { - // Prepare for printing preview with colors - mainWindow.webContents.send('prepare-print-preview', true); - // Give renderer time to prepare, then print + mainWindow.webContents.send('print-preview-styled'); + } +}); + +// Handle actual printing when renderer is ready +ipcMain.on('do-print', (event, { withStyles }) => { + if (mainWindow) { + // Renderer has already hidden UI and prepared the page + // Small delay to ensure everything is rendered setTimeout(() => { mainWindow.webContents.print({ silent: false, - printBackground: true, + printBackground: withStyles, color: true, margin: { marginType: 'default' } }); - }, 100); + }, 50); } }); diff --git a/src/renderer.js b/src/renderer.js index b29e20c..3f54908 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -964,10 +964,13 @@ class TabManager { tab.originalContent = content; tab.isDirty = false; - // Update the editor immediately + // Update the editor and preview const editor = document.getElementById(`editor-${this.activeTabId}`); if (editor) { editor.value = content; + // Update preview after editor is updated + this.updatePreview(this.activeTabId); + this.updateWordCount(); } } else { // Create new tab for the file @@ -990,9 +993,6 @@ class TabManager { } }, 50); } - - this.updatePreview(this.activeTabId); - this.updateWordCount(); this.startAutoSave(); this.addToRecentFiles(filePath); this.updateTabBar(); @@ -1152,18 +1152,16 @@ ipcRenderer.on('adjust-font-size', (event, action) => { updateFontSizes(currentFontSize); }); -// Print preview request handlers - relay to main process +// Print preview request handlers - handle printing directly ipcRenderer.on('print-preview', () => { - ipcRenderer.send('print-preview'); + handlePrintPreview(false); }); ipcRenderer.on('print-preview-styled', () => { - ipcRenderer.send('print-preview-styled'); + handlePrintPreview(true); }); -// Print preview handler - prepare for printing -ipcRenderer.on('prepare-print-preview', (event, withStyles) => { - // Get the active tab's preview element +function handlePrintPreview(withStyles) { const activeTabId = tabManager ? tabManager.activeTabId : 1; const previewContent = document.getElementById(`preview-${activeTabId}`); @@ -1172,30 +1170,27 @@ ipcRenderer.on('prepare-print-preview', (event, withStyles) => { return; } - // Hide UI elements except the preview + // Hide UI elements document.getElementById('toolbar').style.display = 'none'; document.getElementById('tab-bar').style.display = 'none'; document.getElementById('status-bar').style.display = 'none'; - // Hide editor panes (not the whole editor-container) const editorPane = document.getElementById(`editor-pane-${activeTabId}`); if (editorPane) { editorPane.style.display = 'none'; } - // Hide all export dialogs and other overlays - const exportDialog = document.getElementById('export-dialog'); - const batchDialog = document.getElementById('batch-dialog'); - const pdfDialog = document.getElementById('pdf-editor-dialog'); - const converterDialog = document.getElementById('converter-dialog'); - const findDialog = document.getElementById('find-dialog'); - if (exportDialog) exportDialog.style.display = 'none'; - if (batchDialog) batchDialog.style.display = 'none'; - if (pdfDialog) pdfDialog.style.display = 'none'; - if (converterDialog) converterDialog.style.display = 'none'; - if (findDialog) findDialog.style.display = 'none'; + // Hide all dialogs + const dialogs = [ + 'export-dialog', 'batch-dialog', 'pdf-editor-dialog', + 'converter-dialog', 'find-dialog' + ]; + dialogs.forEach(id => { + const dialog = document.getElementById(id); + if (dialog) dialog.style.display = 'none'; + }); - // Make preview full screen for printing + // Apply print-mode to preview pane const previewPane = document.getElementById(`preview-pane-${activeTabId}`); if (previewPane) { previewPane.classList.add('print-mode'); @@ -1204,29 +1199,34 @@ ipcRenderer.on('prepare-print-preview', (event, withStyles) => { } } - // Re-show everything after print - setTimeout(() => { - document.getElementById('toolbar').style.display = ''; - document.getElementById('tab-bar').style.display = ''; - document.getElementById('status-bar').style.display = ''; + // Use requestAnimationFrame twice to ensure browser has rendered the DOM changes + requestAnimationFrame(() => { + requestAnimationFrame(() => { + // Now tell main process to print - the DOM is fully rendered + ipcRenderer.send('do-print', { withStyles }); - // Restore editor pane - if (editorPane) { - editorPane.style.display = ''; - } + // Restore UI after print + setTimeout(() => { + document.getElementById('toolbar').style.display = ''; + document.getElementById('tab-bar').style.display = ''; + document.getElementById('status-bar').style.display = ''; - // Restore dialog visibility if they were open - if (exportDialog) exportDialog.style.display = ''; - if (batchDialog) batchDialog.style.display = ''; - if (pdfDialog) pdfDialog.style.display = ''; - if (converterDialog) converterDialog.style.display = ''; - if (findDialog) findDialog.style.display = ''; + if (editorPane) { + editorPane.style.display = ''; + } - if (previewPane) { - previewPane.classList.remove('print-mode', 'print-no-styles'); - } - }, 500); -}); + dialogs.forEach(id => { + const dialog = document.getElementById(id); + if (dialog) dialog.style.display = ''; + }); + + if (previewPane) { + previewPane.classList.remove('print-mode', 'print-no-styles'); + } + }, 100); + }); + }); +} // Export Dialog functionality let currentExportFormat = null;