Ai
1 Star 0 Fork 0

ZXJ/markdown编辑器

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
main.js 10.11 KB
一键复制 编辑 原始数据 按行查看 历史
ZXJ 提交于 2025-05-09 11:32 +08:00 . refactor(main): 优化文件加载逻辑
const { app, BrowserWindow, ipcMain, dialog, globalShortcut } = require('electron');
const path = require('path');
const fs = require('fs');
const isDev = process.env.NODE_ENV === 'development';
// 存储所有窗口的引用
const windows = new Set();
let pendingFilePath = null;
// 设置应用程序图标
if (process.platform === 'win32') {
app.setAppUserModelId("com.mdnote.app");
}
// 处理文件打开
function handleFileOpen(filePath, targetWindow = null) {
if (!filePath) {
console.log('No file path provided');
return;
}
console.log('Handling file open:', filePath);
try {
// 确保文件路径是绝对路径
const absolutePath = path.resolve(filePath);
console.log('Absolute file path:', absolutePath);
// 检查文件是否存在
if (!fs.existsSync(absolutePath)) {
console.error('File does not exist:', absolutePath);
return;
}
const content = fs.readFileSync(absolutePath, 'utf-8');
console.log('File content read successfully');
let win = targetWindow;
if (!win) {
console.log('No window specified, creating new window');
win = createWindow(absolutePath);
return;
}
// 等待窗口加载完成后发送内容
const sendContent = () => {
if (!win) return;
console.log('Sending content to window');
win.webContents.send('file-opened', {
content: content,
path: absolutePath
});
};
if (win.webContents.isLoading()) {
win.webContents.once('did-finish-load', () => {
setTimeout(sendContent, 100);
});
} else {
sendContent();
}
if (win.isMinimized()) {
win.restore();
}
win.focus();
} catch (error) {
console.error('Error reading file:', error);
dialog.showErrorBox('打开文件失败', `无法打开文件: ${error.message}`);
}
}
function createWindow(initialFilePath = null) {
const iconPath = isDev
? path.join(__dirname, './build/icons/icon.ico')
: path.join(process.resourcesPath, 'icon.ico');
// 提前读取文件内容
let initialContent = null;
if (initialFilePath) {
try {
initialContent = fs.readFileSync(initialFilePath, 'utf-8');
} catch (error) {
console.error('Error reading initial file:', error);
dialog.showErrorBox('打开文件失败', `无法打开文件: ${error.message}`);
return null;
}
}
const newWindow = new BrowserWindow({
width: 1200,
height: 800,
autoHideMenuBar: true,
icon: iconPath,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
webSecurity: true,
allowRunningInsecureContent: false,
preload: path.join(__dirname, 'preload.js')
},
show: false // 先不显示窗口
});
// 设置任务栏图标
if (process.platform === 'win32') {
newWindow.setThumbarButtons([]);
}
// 设置 CSP
newWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
"default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: https:;",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' blob: https:;",
"script-src-elem 'self' 'unsafe-inline' 'unsafe-eval' blob: https:;",
"style-src 'self' 'unsafe-inline' blob: https:;",
"style-src-elem 'self' 'unsafe-inline' blob: https:;",
"img-src 'self' data: blob: https:;",
"font-src 'self' data: https:;",
"connect-src 'self' ws: wss: https:;"
].join(' ')
}
});
});
// 设置 webSecurity 为 false(仅在开发环境)
if (isDev) {
newWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Access-Control-Allow-Origin': ['*']
}
});
});
}
// 注册打开 DevTools 的快捷键
globalShortcut.register('CommandOrControl+Shift+I', () => {
if (newWindow) {
newWindow.webContents.toggleDevTools();
}
});
// 添加右键菜单
newWindow.webContents.on('context-menu', (event, params) => {
newWindow.webContents.toggleDevTools();
});
// 监听窗口加载完成事件
newWindow.webContents.on('did-finish-load', () => {
console.log('Window loaded');
if (pendingFilePath) {
console.log('Processing pending file:', pendingFilePath);
const filePath = pendingFilePath;
pendingFilePath = null;
// 延迟一下再发送文件内容,确保渲染进程已完全准备好
setTimeout(() => {
handleFileOpen(filePath, newWindow);
}, 100);
}
});
// 监听 DOM 准备就绪事件
newWindow.webContents.on('dom-ready', () => {
console.log('DOM is ready');
});
// 当窗口准备好时再显示
newWindow.once('ready-to-show', () => {
newWindow.show();
});
if (isDev) {
newWindow.loadURL('http://localhost:5173');
newWindow.webContents.openDevTools();
} else {
const indexPath = path.join(__dirname, 'dist', 'index.html');
newWindow.loadFile(indexPath);
}
// 当窗口加载完成时,如果有初始文件内容,则立即发送
if (initialContent !== null) {
newWindow.webContents.once('did-finish-load', () => {
newWindow.webContents.send('file-opened', {
content: initialContent,
path: initialFilePath
});
});
}
// 当窗口关闭时从集合中移除
newWindow.on('closed', () => {
windows.delete(newWindow);
});
// 将窗口添加到集合中
windows.add(newWindow);
return newWindow;
}
// 处理命令行参数
function handleCommandLineArgs() {
const args = process.argv.slice(1);
console.log('Command line args:', args);
const mdFile = args.find(arg => {
// 检查参数是否以 .md 结尾,并且不是命令行选项
return arg.toLowerCase().endsWith('.md') && !arg.startsWith('--');
});
if (mdFile) {
console.log('Found MD file in args:', mdFile);
return path.resolve(mdFile);
}
console.log('No MD file found in args');
return null;
}
// 处理 Windows 文件关联打开
if (process.platform === 'win32') {
// 移除单实例锁,允许多实例运行
const gotTheLock = true;
app.on('second-instance', (event, commandLine, workingDirectory) => {
console.log('Second instance detected');
console.log('Command line:', commandLine);
// 为新实例创建新窗口
const filePath = commandLine.find(arg => arg.toLowerCase().endsWith('.md'));
if (filePath) {
createWindow(filePath);
} else {
createWindow();
}
});
// 设置为默认的 .md 文件处理程序
app.setAsDefaultProtocolClient('mdnote');
}
// 应用程序就绪事件
app.whenReady().then(() => {
console.log('App is ready');
// 处理启动参数
const filePath = handleCommandLineArgs();
if (filePath) {
console.log('Initial file path:', filePath);
createWindow(filePath);
} else {
createWindow();
}
app.on('activate', () => {
if (windows.size === 0) {
createWindow();
}
});
});
// 处理文件保存
ipcMain.on('save-file', (event, { content, path: filePath }) => {
console.log('Save file request received');
console.log('Content length to save:', content.length);
console.log('Content preview:', content.substring(0, 100));
try {
const targetPath = filePath || pendingFilePath;
if (!targetPath) {
console.error('No file path for saving');
event.reply('save-file-reply', {
success: false,
error: 'No file path specified'
});
return;
}
// 确保文件路径是绝对路径
const absolutePath = path.resolve(targetPath);
console.log('Absolute save path:', absolutePath);
// 检查文件是否可写
try {
fs.accessSync(absolutePath, fs.constants.W_OK);
} catch (error) {
console.error('File is not writable:', error);
event.reply('save-file-reply', {
success: false,
error: `File is not writable: ${error.message}`
});
return;
}
// 写入文件
fs.writeFileSync(absolutePath, content, 'utf-8');
console.log('File saved successfully');
// 更新当前文件路径
pendingFilePath = absolutePath;
// 验证文件是否正确保存
const savedContent = fs.readFileSync(absolutePath, 'utf-8');
if (savedContent === content) {
console.log('File content verified');
event.reply('save-file-reply', {
success: true,
path: absolutePath
});
} else {
console.error('File content verification failed');
event.reply('save-file-reply', {
success: false,
error: 'File content verification failed'
});
}
} catch (error) {
console.error('Error saving file:', error);
event.reply('save-file-reply', {
success: false,
error: error.message
});
}
});
// 处理另存为
ipcMain.on('save-file-as', (event, { content, defaultPath }) => {
console.log('Save file as request received');
dialog.showSaveDialog({
defaultPath: defaultPath || path.join(app.getPath('documents'), 'untitled.md'),
filters: [{ name: 'Markdown', extensions: ['md'] }]
}).then(result => {
if (!result.canceled && result.filePath) {
try {
fs.writeFileSync(result.filePath, content, 'utf-8');
pendingFilePath = result.filePath;
console.log('File saved successfully to:', result.filePath);
event.reply('save-file-reply', {
success: true,
path: result.filePath
});
} catch (error) {
console.error('Error saving file:', error);
event.reply('save-file-reply', {
success: false,
error: error.message
});
}
}
}).catch(error => {
console.error('Error in save dialog:', error);
event.reply('save-file-reply', {
success: false,
error: error.message
});
});
});
// 处理所有窗口关闭事件
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// 应用退出时清理
app.on('will-quit', () => {
globalShortcut.unregisterAll();
});
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zxj6/markdown-editor.git
git@gitee.com:zxj6/markdown-editor.git
zxj6
markdown-editor
markdown编辑器
master

搜索帮助