perf: drawio文件支持导出pdf文件

This commit is contained in:
kuaifan 2023-02-13 11:35:07 +08:00
parent 8b4244d237
commit e8e873f0da
3 changed files with 415 additions and 112 deletions

View File

@ -1,73 +1,66 @@
const {contextBridge, ipcRenderer} = require("electron") const {
contextBridge,
ipcRenderer
} = require("electron");
let reqId = 1 let reqId = 1;
let reqInfo = {} let reqInfo = {};
let msgChangedListeners = {} let fileChangedListeners = {};
let fileChangedListeners = {}
ipcRenderer.on('mainResp', (event, resp) => { ipcRenderer.on('mainResp', (event, resp) => {
let callbacks = reqInfo[resp.reqId] let callbacks = reqInfo[resp.reqId];
if (resp.error) { if (resp.error) {
callbacks.error(resp.msg, resp.e) callbacks.error(resp.msg, resp.e);
} else { } else {
callbacks.callback(resp.data) callbacks.callback(resp.data);
} }
delete reqInfo[resp.reqId] delete reqInfo[resp.reqId];
}) });
ipcRenderer.on('fileChanged', (event, resp) => { ipcRenderer.on('fileChanged', (event, resp) => {
let listener = fileChangedListeners[resp.path] let listener = fileChangedListeners[resp.path];
if (listener) { if (listener) {
listener(resp.curr, resp.prev) listener(resp.curr, resp.prev);
} }
}) });
contextBridge.exposeInMainWorld( contextBridge.exposeInMainWorld(
'electron', { 'electron', {
request: (msg, callback, error) => { request: (msg, callback, error) => {
msg.reqId = reqId++ msg.reqId = reqId++;
reqInfo[msg.reqId] = {callback: callback, error: error} reqInfo[msg.reqId] = {callback: callback, error: error};
//TODO Maybe a special function for this better than this hack?
//File watch special case where the callback is called multiple times
if (msg.action == 'watchFile') { if (msg.action == 'watchFile') {
fileChangedListeners[msg.path] = msg.listener fileChangedListeners[msg.path] = msg.listener;
delete msg.listener delete msg.listener;
} }
ipcRenderer.send('rendererReq', msg) ipcRenderer.send('rendererReq', msg);
}, },
registerMsgListener: (action, callback) => { registerMsgListener: function (action, callback) {
msgChangedListeners[action] = (event, args) => { ipcRenderer.on(action, function (event, args) {
callback(args) callback(args);
} });
ipcRenderer.on(action, msgChangedListeners[action])
}, },
registerMsgListenOnce: (action, callback) => { sendMessage: function (action, args) {
msgChangedListeners[action] = (event, args) => { ipcRenderer.send(action, args);
callback(args)
}
ipcRenderer.once(action, msgChangedListeners[action])
}, },
removeMsgListener: (action) => { listenOnce: function (action, callback) {
if (typeof msgChangedListeners[action] === "function") { ipcRenderer.once(action, function (event, args) {
ipcRenderer.removeListener(action, msgChangedListeners[action]) callback(args);
delete msgChangedListeners[action] });
}
},
sendMessage: (action, args) => {
ipcRenderer.send(action, args)
},
sendSyncMessage: (action, args) => {
ipcRenderer.sendSync(action, args)
} }
} }
) );
contextBridge.exposeInMainWorld( contextBridge.exposeInMainWorld(
'process', { 'process', {
type: process.type, type: process.type,
versions: process.versions versions: process.versions
} }
) );

450
electron/electron.js vendored
View File

@ -11,6 +11,14 @@ const crc = require('crc');
const zlib = require('zlib'); const zlib = require('zlib');
const utils = require('./utils'); const utils = require('./utils');
const config = require('./package.json'); const config = require('./package.json');
const spawn = require("child_process").spawn;
const isMac = process.platform === 'darwin'
const isWin = process.platform === 'win32'
const allowedUrls = /^(?:https?|mailto|tel|callto):/i;
let enableStoreBkp = true;
let dialogOpen = false;
let enablePlugins = false;
let mainWindow = null, let mainWindow = null,
mainTray = null, mainTray = null,
@ -605,6 +613,7 @@ ipcMain.on('updateQuitAndInstall', (event) => {
//================================================================ //================================================================
const MICRON_TO_PIXEL = 264.58 //264.58 micron = 1 pixel const MICRON_TO_PIXEL = 264.58 //264.58 micron = 1 pixel
const PIXELS_PER_INCH = 100.117 // Usually it is 100 pixels per inch but this give better results
const PNG_CHUNK_IDAT = 1229209940; const PNG_CHUNK_IDAT = 1229209940;
const LARGE_IMAGE_AREA = 30000000; const LARGE_IMAGE_AREA = 30000000;
@ -727,7 +736,6 @@ function writePngWithText(origBuff, key, text, compressed, base64encoded) {
//TODO Create a lightweight html file similar to export3.html for exporting to vsdx //TODO Create a lightweight html file similar to export3.html for exporting to vsdx
function exportVsdx(event, args, directFinalize) { function exportVsdx(event, args, directFinalize) {
let win = new BrowserWindow({ let win = new BrowserWindow({
width: 1280, width: 1280,
height: 800, height: 800,
@ -829,7 +837,7 @@ function exportDiagram(event, args, directFinalize) {
preload: path.join(__dirname, 'electron-preload.js'), preload: path.join(__dirname, 'electron-preload.js'),
backgroundThrottling: false, backgroundThrottling: false,
contextIsolation: true, contextIsolation: true,
nativeWindowOpen: true disableBlinkFeatures: 'Auxclick' // Is this needed?
}, },
show: false, show: false,
frame: false, frame: false,
@ -837,7 +845,15 @@ function exportDiagram(event, args, directFinalize) {
transparent: args.format == 'png' && (args.bg == null || args.bg == 'none'), transparent: args.format == 'png' && (args.bg == null || args.bg == 'none'),
}); });
browser.loadURL(`file://${__dirname}/export3.html`); if (devloadUrl) {
browser.loadURL(devloadUrl + 'drawio/webapp/export3.html').then(_ => {
})
} else {
browser.loadFile('./public/drawio/webapp/export3.html').then(_ => {
})
}
const contents = browser.webContents; const contents = browser.webContents;
let pageByPage = (args.format == 'pdf' && !args.print), from, to, pdfs; let pageByPage = (args.format == 'pdf' && !args.print), from, to, pdfs;
@ -887,22 +903,18 @@ function exportDiagram(event, args, directFinalize) {
//A workaround to detect errors in the input file or being empty file //A workaround to detect errors in the input file or being empty file
hasError = true; hasError = true;
} else { } else {
//Chrome generates Pdf files larger than requested pixels size and requires scaling
let fixingScale = 0.959;
let w = Math.ceil(bounds.width * fixingScale);
// +0.1 fixes cases where adding 1px below is not enough
// Increase this if more cropped PDFs have extra empty pages
let h = Math.ceil(bounds.height * fixingScale + 0.1);
pdfOptions = { pdfOptions = {
printBackground: true, printBackground: true,
pageSize: { pageSize: {
width: w * MICRON_TO_PIXEL, width: bounds.width / PIXELS_PER_INCH,
height: (h + 2) * MICRON_TO_PIXEL //the extra 2 pixels to prevent adding an extra empty page height: (bounds.height + 2) / PIXELS_PER_INCH //the extra 2 pixels to prevent adding an extra empty page
}, },
marginsType: 1 // no margin margins: {
top: 0,
bottom: 0,
left: 0,
right: 0
} // no margin
} }
} }
@ -1035,12 +1047,188 @@ ipcMain.on('export', exportDiagram);
// Renderer Helper functions // Renderer Helper functions
//================================================================ //================================================================
const {COPYFILE_EXCL} = fs.constants; const {O_SYNC, O_CREAT, O_WRONLY, O_TRUNC, O_RDONLY} = fs.constants;
const DRAFT_PREFEX = '~$'; const DRAFT_PREFEX = '.$';
const OLD_DRAFT_PREFEX = '~$';
const DRAFT_EXT = '.dtmp'; const DRAFT_EXT = '.dtmp';
const BKP_PREFEX = '~$'; const BKP_PREFEX = '.$';
const OLD_BKP_PREFEX = '~$';
const BKP_EXT = '.bkp'; const BKP_EXT = '.bkp';
/**
* Checks the file content type
* Confirm content is xml, pdf, png, jpg, svg, vsdx ...
*/
function checkFileContent(body, enc) {
if (body != null) {
let head, headBinay;
if (typeof body === 'string') {
if (enc == 'base64') {
headBinay = Buffer.from(body.substring(0, 22), 'base64');
head = headBinay.toString();
} else {
head = body.substring(0, 16);
headBinay = Buffer.from(head);
}
} else {
head = new TextDecoder("utf-8").decode(body.subarray(0, 16));
headBinay = body;
}
let c1 = head[0],
c2 = head[1],
c3 = head[2],
c4 = head[3],
c5 = head[4],
c6 = head[5],
c7 = head[6],
c8 = head[7],
c9 = head[8],
c10 = head[9],
c11 = head[10],
c12 = head[11],
c13 = head[12],
c14 = head[13],
c15 = head[14],
c16 = head[15];
let cc1 = headBinay[0],
cc2 = headBinay[1],
cc3 = headBinay[2],
cc4 = headBinay[3],
cc5 = headBinay[4],
cc6 = headBinay[5],
cc7 = headBinay[6],
cc8 = headBinay[7],
cc9 = headBinay[8],
cc10 = headBinay[9],
cc11 = headBinay[10],
cc12 = headBinay[11],
cc13 = headBinay[12],
cc14 = headBinay[13],
cc15 = headBinay[14],
cc16 = headBinay[15];
if (c1 == '<') {
// text/html
if (c2 == '!'
|| ((c2 == 'h'
&& (c3 == 't' && c4 == 'm' && c5 == 'l'
|| c3 == 'e' && c4 == 'a' && c5 == 'd')
|| (c2 == 'b' && c3 == 'o' && c4 == 'd'
&& c5 == 'y')))
|| ((c2 == 'H'
&& (c3 == 'T' && c4 == 'M' && c5 == 'L'
|| c3 == 'E' && c4 == 'A' && c5 == 'D')
|| (c2 == 'B' && c3 == 'O' && c4 == 'D'
&& c5 == 'Y')))) {
return true;
}
// application/xml
if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l'
&& c6 == ' ') {
return true;
}
// application/svg+xml
if (c2 == 's' && c3 == 'v' && c4 == 'g' && c5 == ' ') {
return true;
}
}
// big and little (identical) endian UTF-8 encodings, with BOM
// application/xml
if (cc1 == 0xef && cc2 == 0xbb && cc3 == 0xbf) {
if (c4 == '<' && c5 == '?' && c6 == 'x') {
return true;
}
}
// big and little endian UTF-16 encodings, with byte order mark
// application/xml
if (cc1 == 0xfe && cc2 == 0xff) {
if (cc3 == 0 && c4 == '<' && cc5 == 0 && c6 == '?' && cc7 == 0
&& c8 == 'x') {
return true;
}
}
// application/xml
if (cc1 == 0xff && cc2 == 0xfe) {
if (c3 == '<' && cc4 == 0 && c5 == '?' && cc6 == 0 && c7 == 'x'
&& cc8 == 0) {
return true;
}
}
// big and little endian UTF-32 encodings, with BOM
// application/xml
if (cc1 == 0x00 && cc2 == 0x00 && cc3 == 0xfe && cc4 == 0xff) {
if (cc5 == 0 && cc6 == 0 && cc7 == 0 && c8 == '<' && cc9 == 0
&& cc10 == 0 && cc11 == 0 && c12 == '?' && cc13 == 0
&& cc14 == 0 && cc15 == 0 && c16 == 'x') {
return true;
}
}
// application/xml
if (cc1 == 0xff && cc2 == 0xfe && cc3 == 0x00 && cc4 == 0x00) {
if (c5 == '<' && cc6 == 0 && cc7 == 0 && cc8 == 0 && c9 == '?'
&& cc10 == 0 && cc11 == 0 && cc12 == 0 && c13 == 'x'
&& cc14 == 0 && cc15 == 0 && cc16 == 0) {
return true;
}
}
// application/pdf (%PDF-)
if (cc1 == 37 && cc2 == 80 && cc3 == 68 && cc4 == 70 && cc5 == 45) {
return true;
}
// image/png
if ((cc1 == 137 && cc2 == 80 && cc3 == 78 && cc4 == 71 && cc5 == 13
&& cc6 == 10 && cc7 == 26 && cc8 == 10) ||
(cc1 == 194 && cc2 == 137 && cc3 == 80 && cc4 == 78 && cc5 == 71 && cc6 == 13 //Our embedded PNG+XML
&& cc7 == 10 && cc8 == 26 && cc9 == 10)) {
return true;
}
// image/jpeg
if (cc1 == 0xFF && cc2 == 0xD8 && cc3 == 0xFF) {
if (cc4 == 0xE0 || cc4 == 0xEE) {
return true;
}
/**
* File format used by digital cameras to store images.
* Exif Format can be read by any application supporting
* JPEG. Exif Spec can be found at:
* http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
*/
if ((cc4 == 0xE1) && (c7 == 'E' && c8 == 'x' && c9 == 'i'
&& c10 == 'f' && cc11 == 0)) {
return true;
}
}
// vsdx, vssx (also zip, jar, odt, ods, odp, docx, xlsx, pptx, apk, aar)
if (cc1 == 0x50 && cc2 == 0x4B && cc3 == 0x03 && cc4 == 0x04) {
return true;
} else if (cc1 == 0x50 && cc2 == 0x4B && cc3 == 0x03 && cc4 == 0x06) {
return true;
}
// mxfile, mxlibrary, mxGraphModel
if (c1 == '<' && c2 == 'm' && c3 == 'x') {
return true;
}
}
return false;
}
function isConflict(origStat, stat) { function isConflict(origStat, stat) {
return stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs; return stat != null && origStat != null && stat.mtimeMs != origStat.mtimeMs;
} }
@ -1067,6 +1255,25 @@ async function getFileDrafts(fileObject) {
uniquePart = '_' + counter++; uniquePart = '_' + counter++;
} while (fs.existsSync(draftFileName)); //TODO this assume continuous drafts names } while (fs.existsSync(draftFileName)); //TODO this assume continuous drafts names
//Port old draft files to new prefex
counter = 1;
uniquePart = '';
let draftExists = false;
do {
draftFileName = path.join(path.dirname(filePath), OLD_DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT);
draftExists = fs.existsSync(draftFileName);
if (draftExists) {
const newDraftFileName = path.join(path.dirname(filePath), DRAFT_PREFEX + path.basename(filePath) + uniquePart + DRAFT_EXT);
await fsProm.rename(draftFileName, newDraftFileName);
draftsPaths.push(newDraftFileName);
}
uniquePart = '_' + counter++;
} while (draftExists); //TODO this assume continuous drafts names
//Skip the first null element
for (let i = 1; i < draftsPaths.length; i++) { for (let i = 1; i < draftsPaths.length; i++) {
try { try {
let stat = await fsProm.lstat(draftsPaths[i]); let stat = await fsProm.lstat(draftsPaths[i]);
@ -1084,75 +1291,126 @@ async function getFileDrafts(fileObject) {
} }
async function saveDraft(fileObject, data) { async function saveDraft(fileObject, data) {
if (data == null || data.length == 0) { if (!checkFileContent(data)) {
throw new Error('empty data'); throw new Error('Invalid file data');
} else { } else {
let draftFileName = fileObject.draftFileName || getDraftFileName(fileObject); let draftFileName = fileObject.draftFileName || getDraftFileName(fileObject);
await fsProm.writeFile(draftFileName, data, 'utf8'); await fsProm.writeFile(draftFileName, data, 'utf8');
if (isWin) {
try {
// Add Hidden attribute:
spawn('attrib', ['+h', draftFileName], {shell: true});
} catch (e) {
}
}
return draftFileName; return draftFileName;
} }
} }
async function saveFile(fileObject, data, origStat, overwrite, defEnc) { async function saveFile(fileObject, data, origStat, overwrite, defEnc) {
if (!checkFileContent(data)) {
throw new Error('Invalid file data');
}
let retryCount = 0; let retryCount = 0;
let backupCreated = false; let backupCreated = false;
let bkpPath = path.join(path.dirname(fileObject.path), BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT); let bkpPath = path.join(path.dirname(fileObject.path), BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT);
const oldBkpPath = path.join(path.dirname(fileObject.path), OLD_BKP_PREFEX + path.basename(fileObject.path) + BKP_EXT);
let writeEnc = defEnc || fileObject.encoding;
let writeFile = async function () { let writeFile = async function () {
if (data == null || data.length == 0) { let fh;
throw new Error('empty data');
} else {
let writeEnc = defEnc || fileObject.encoding;
await fsProm.writeFile(fileObject.path, data, writeEnc); try {
let stat2 = await fsProm.stat(fileObject.path); // O_SYNC is for sync I/O and reduce risk of file corruption
let writtenData = await fsProm.readFile(fileObject.path, writeEnc); fh = await fsProm.open(fileObject.path, O_SYNC | O_CREAT | O_WRONLY | O_TRUNC);
await fsProm.writeFile(fh, data, writeEnc);
} finally {
await fh?.close();
}
if (data != writtenData) { let stat2 = await fsProm.stat(fileObject.path);
retryCount++; // Workaround for possible writing errors is to check the written
// contents of the file and retry 3 times before showing an error
let writtenData = await fsProm.readFile(fileObject.path, writeEnc);
if (retryCount < 3) { if (data != writtenData) {
return await writeFile(); retryCount++;
} else {
throw new Error('all saving trials failed'); if (retryCount < 3) {
} return await writeFile();
} else { } else {
if (backupCreated) { throw new Error('all saving trials failed');
fs.unlink(bkpPath, (err) => {
}); //Ignore errors!
}
return stat2;
} }
} else {
//We'll keep the backup file in case the original file is corrupted. TODO When should we delete the backup file?
if (backupCreated) {
//fs.unlink(bkpPath, (err) => {}); //Ignore errors!
//Delete old backup file with old prefix
if (fs.existsSync(oldBkpPath)) {
fs.unlink(oldBkpPath, (err) => {
}); //Ignore errors
}
}
return stat2;
} }
}; };
async function doSaveFile() { async function doSaveFile(isNew) {
try { if (enableStoreBkp && !isNew) {
await fsProm.copyFile(fileObject.path, bkpPath, COPYFILE_EXCL); //Copy file to backup file (after conflict and stat is checked)
backupCreated = true; let bkpFh;
} catch (e) {
} //Ignore try {
//Use file read then write to open the backup file direct sync write to reduce the chance of file corruption
let fileContent = await fsProm.readFile(fileObject.path, writeEnc);
bkpFh = await fsProm.open(bkpPath, O_SYNC | O_CREAT | O_WRONLY | O_TRUNC);
await fsProm.writeFile(bkpFh, fileContent, writeEnc);
backupCreated = true;
} catch (e) {
if (__DEV__) {
console.log('Backup file writing failed', e); //Ignore
}
} finally {
await bkpFh?.close();
if (isWin) {
try {
// Add Hidden attribute:
spawn('attrib', ['+h', bkpPath], {shell: true});
} catch (e) {
}
}
}
}
return await writeFile(); return await writeFile();
} }
if (overwrite) { if (overwrite) {
return await doSaveFile(); return await doSaveFile(true);
} else { } else {
let stat = fs.existsSync(fileObject.path) ? let stat = fs.existsSync(fileObject.path) ?
await fsProm.stat(fileObject.path) : null; await fsProm.stat(fileObject.path) : null;
if (stat && isConflict(origStat, stat)) { if (stat && isConflict(origStat, stat)) {
new Error('conflict'); throw new Error('conflict');
} else { } else {
return await doSaveFile(); return await doSaveFile(stat == null);
} }
} }
} }
async function writeFile(path, data, enc) { async function writeFile(path, data, enc) {
return await fsProm.writeFile(path, data, enc); if (!checkFileContent(data, enc)) {
throw new Error('Invalid file data');
} else {
return await fsProm.writeFile(path, data, enc);
}
} }
function getAppDataFolder() { function getAppDataFolder() {
@ -1173,6 +1431,7 @@ function getAppDataFolder() {
} }
function getDocumentsFolder() { function getDocumentsFolder() {
//On windows, misconfigured Documents folder cause an exception
try { try {
return app.getPath('documents'); return app.getPath('documents');
} catch (e) { } catch (e) {
@ -1187,7 +1446,9 @@ function checkFileExists(pathParts) {
} }
async function showOpenDialog(defaultPath, filters, properties) { async function showOpenDialog(defaultPath, filters, properties) {
return dialog.showOpenDialogSync({ let win = BrowserWindow.getFocusedWindow();
return dialog.showOpenDialog(win, {
defaultPath: defaultPath, defaultPath: defaultPath,
filters: filters, filters: filters,
properties: properties properties: properties
@ -1195,13 +1456,17 @@ async function showOpenDialog(defaultPath, filters, properties) {
} }
async function showSaveDialog(defaultPath, filters) { async function showSaveDialog(defaultPath, filters) {
return dialog.showSaveDialogSync({ let win = BrowserWindow.getFocusedWindow();
return dialog.showSaveDialog(win, {
defaultPath: defaultPath, defaultPath: defaultPath,
filters: filters filters: filters
}); });
} }
async function installPlugin(filePath) { async function installPlugin(filePath) {
if (!enablePlugins) return {};
let pluginsDir = path.join(getAppDataFolder(), '/plugins'); let pluginsDir = path.join(getAppDataFolder(), '/plugins');
if (!fs.existsSync(pluginsDir)) { if (!fs.existsSync(pluginsDir)) {
@ -1220,13 +1485,25 @@ async function installPlugin(filePath) {
return {pluginName: pluginName, selDir: path.dirname(filePath)}; return {pluginName: pluginName, selDir: path.dirname(filePath)};
} }
function uninstallPlugin(plugin) { function getPluginFile(plugin) {
let pluginsFile = path.join(getAppDataFolder(), '/plugins', plugin); if (!enablePlugins) return null;
if (fs.existsSync(pluginsFile)) { const prefix = path.join(getAppDataFolder(), '/plugins/');
fs.unlinkSync(pluginsFile); const pluginFile = path.join(prefix, plugin);
if (pluginFile.startsWith(prefix) && fs.existsSync(pluginFile)) {
return pluginFile;
}
return null;
}
function uninstallPlugin(plugin) {
const pluginFile = getPluginFile(plugin);
if (pluginFile != null) {
fs.unlinkSync(pluginFile);
} }
return null
} }
function dirname(path_p) { function dirname(path_p) {
@ -1234,7 +1511,13 @@ function dirname(path_p) {
} }
async function readFile(filename, encoding) { async function readFile(filename, encoding) {
return await fsProm.readFile(filename, encoding); let data = await fsProm.readFile(filename, encoding);
if (checkFileContent(data, encoding)) {
return data;
}
throw new Error('Invalid file data');
} }
async function fileStat(file) { async function fileStat(file) {
@ -1265,7 +1548,15 @@ function clipboardAction(method, data) {
} }
async function deleteFile(file) { async function deleteFile(file) {
await fsProm.unlink(file); // Reading the header of the file to confirm it is a file we can delete
let fh = await fsProm.open(file, O_RDONLY);
let buffer = Buffer.allocUnsafe(16);
await fh.read(buffer, 0, 16);
await fh.close();
if (checkFileContent(buffer)) {
await fsProm.unlink(file);
}
} }
function windowAction(method) { function windowAction(method) {
@ -1289,8 +1580,13 @@ function windowAction(method) {
} }
function openExternal(url) { function openExternal(url) {
shell.openExternal(url).then(() => {}).catch(() => {}); //Only open http(s), mailto, tel, and callto links
return null if (allowedUrls.test(url)) {
shell.openExternal(url);
return true;
}
return false;
} }
function watchFile(path) { function watchFile(path) {
@ -1308,12 +1604,14 @@ function watchFile(path) {
} // Ignore } // Ignore
}); });
} }
return null
} }
function unwatchFile(path) { function unwatchFile(path) {
fs.unwatchFile(path); fs.unwatchFile(path);
return null }
function getCurDir() {
return __dirname;
} }
ipcMain.on("rendererReq", async (event, args) => { ipcMain.on("rendererReq", async (event, args) => {
@ -1333,20 +1631,23 @@ ipcMain.on("rendererReq", async (event, args) => {
case 'getFileDrafts': case 'getFileDrafts':
ret = await getFileDrafts(args.fileObject); ret = await getFileDrafts(args.fileObject);
break; break;
case 'getAppDataFolder':
ret = getAppDataFolder();
break;
case 'getDocumentsFolder': case 'getDocumentsFolder':
ret = await getDocumentsFolder(); ret = await getDocumentsFolder();
break; break;
case 'checkFileExists': case 'checkFileExists':
ret = checkFileExists(args.pathParts); ret = await checkFileExists(args.pathParts);
break; break;
case 'showOpenDialog': case 'showOpenDialog':
dialogOpen = true;
ret = await showOpenDialog(args.defaultPath, args.filters, args.properties); ret = await showOpenDialog(args.defaultPath, args.filters, args.properties);
ret = ret.filePaths;
dialogOpen = false;
break; break;
case 'showSaveDialog': case 'showSaveDialog':
dialogOpen = true;
ret = await showSaveDialog(args.defaultPath, args.filters); ret = await showSaveDialog(args.defaultPath, args.filters);
ret = ret.canceled ? null : ret.filePath;
dialogOpen = false;
break; break;
case 'installPlugin': case 'installPlugin':
ret = await installPlugin(args.filePath); ret = await installPlugin(args.filePath);
@ -1354,14 +1655,20 @@ ipcMain.on("rendererReq", async (event, args) => {
case 'uninstallPlugin': case 'uninstallPlugin':
ret = await uninstallPlugin(args.plugin); ret = await uninstallPlugin(args.plugin);
break; break;
case 'getPluginFile':
ret = await getPluginFile(args.plugin);
break;
case 'isPluginsEnabled':
ret = enablePlugins;
break;
case 'dirname': case 'dirname':
ret = dirname(args.path); ret = await dirname(args.path);
break; break;
case 'readFile': case 'readFile':
ret = await readFile(args.filename, args.encoding); ret = await readFile(args.filename, args.encoding);
break; break;
case 'clipboardAction': case 'clipboardAction':
ret = clipboardAction(args.method, args.data); ret = await clipboardAction(args.method, args.data);
break; break;
case 'deleteFile': case 'deleteFile':
ret = await deleteFile(args.file); ret = await deleteFile(args.file);
@ -1373,7 +1680,7 @@ ipcMain.on("rendererReq", async (event, args) => {
ret = await isFileWritable(args.file); ret = await isFileWritable(args.file);
break; break;
case 'windowAction': case 'windowAction':
ret = windowAction(args.method); ret = await windowAction(args.method);
break; break;
case 'openExternal': case 'openExternal':
ret = await openExternal(args.url); ret = await openExternal(args.url);
@ -1384,6 +1691,9 @@ ipcMain.on("rendererReq", async (event, args) => {
case 'unwatchFile': case 'unwatchFile':
ret = await unwatchFile(args.path); ret = await unwatchFile(args.path);
break; break;
case 'getCurDir':
ret = await getCurDir();
break;
} }
event.reply('mainResp', {success: true, data: ret, reqId: args.reqId}); event.reply('mainResp', {success: true, data: ret, reqId: args.reqId});

View File

@ -32,7 +32,7 @@
"@electron-forge/maker-squirrel": "^6.0.4", "@electron-forge/maker-squirrel": "^6.0.4",
"@electron-forge/maker-zip": "^6.0.4", "@electron-forge/maker-zip": "^6.0.4",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"electron": "^22.2.0", "electron": "^23.0.0",
"electron-builder": "^23.6.0", "electron-builder": "^23.6.0",
"electron-notarize": "^1.2.2", "electron-notarize": "^1.2.2",
"form-data": "^4.0.0", "form-data": "^4.0.0",