dootask/electron/electron-menu.js

169 lines
5.7 KiB
JavaScript
Vendored

const {
clipboard,
nativeImage,
Menu,
MenuItem,
dialog,
shell,
} = require('electron')
const fs = require('fs')
const url = require('url')
const request = require("request");
const MAILTO_PREFIX = "mailto:";
const PERMITTED_URL_SCHEMES = ["http:", "https:", MAILTO_PREFIX];
const electronMenu = {
language: {
openInBrowser: "在浏览器中打开",
saveImageAs: "图片存储为...",
copyImage: "复制图片",
copyEmailAddress: "复制电子邮件地址",
copyLinkAddress: "复制链接地址",
copyImageAddress: "复制图片地址",
failedToSaveImage: "图片保存失败",
theImageFailedToSave: "图片无法保存",
},
setLanguage(language) {
this.language = Object.assign(this.language, language);
},
safeOpenURL(target) {
const parsedUrl = url.parse(target);
if (PERMITTED_URL_SCHEMES.includes(parsedUrl.protocol)) {
const newTarget = url.format(parsedUrl);
shell.openExternal(newTarget).then(r => {
});
}
},
isBlob(url) {
return url.startsWith("blob:");
},
isDataUrl(url) {
return url.startsWith("data:");
},
isBlobOrDataUrl(url) {
return electronMenu.isBlob(url) || electronMenu.isDataUrl(url);
},
async saveImageAs(url, params) {
const targetFileName = params.suggestedFilename || params.altText || "image.png";
const {filePath} = await dialog.showSaveDialog({
defaultPath: targetFileName,
});
if (!filePath) return; // user cancelled dialog
try {
if (electronMenu.isBlobOrDataUrl(url)) {
await electronMenu.writeNativeImage(filePath, nativeImage.createFromDataURL(url));
} else {
const writeStream = fs.createWriteStream(filePath)
const readStream = request(url)
readStream.pipe(writeStream);
readStream.on('end', function (response) {
writeStream.end();
});
}
} catch (err) {
await dialog.showMessageBox({
type: "error",
title: electronMenu.language.failedToSaveImage,
message: electronMenu.language.theImageFailedToSave,
});
}
},
writeNativeImage(filePath, img) {
switch (filePath.split(".").pop()?.toLowerCase()) {
case "jpg":
case "jpeg":
return fs.promises.writeFile(filePath, img.toJPEG(100));
case "bmp":
return fs.promises.writeFile(filePath, img.toBitmap());
case "png":
default:
return fs.promises.writeFile(filePath, img.toPNG());
}
},
webContentsMenu(webContents) {
webContents.on("context-menu", function (e, params) {
if (params.linkURL || params.srcURL) {
const url = params.linkURL || params.srcURL;
const popupMenu = new Menu();
if (!electronMenu.isBlobOrDataUrl(url)) {
popupMenu.append(
new MenuItem({
label: electronMenu.language.openInBrowser,
accelerator: "o",
click() {
electronMenu.safeOpenURL(url);
},
}),
);
}
if (params.hasImageContents) {
if (!electronMenu.isBlob(url)) {
popupMenu.append(
new MenuItem({
label: electronMenu.language.saveImageAs,
accelerator: "s",
click: async function () {
await electronMenu.saveImageAs(url, params);
},
}),
);
}
popupMenu.append(
new MenuItem({
label: electronMenu.language.copyImage,
accelerator: "c",
click() {
webContents.copyImageAt(params.x, params.y);
},
}),
);
}
if (!electronMenu.isBlobOrDataUrl(url)) {
if (url.startsWith(MAILTO_PREFIX)) {
popupMenu.append(
new MenuItem({
label: electronMenu.language.copyEmailAddress,
accelerator: "a",
click() {
clipboard.writeText(url.substring(MAILTO_PREFIX.length));
},
}),
);
} else {
popupMenu.append(
new MenuItem({
label: params.hasImageContents ? electronMenu.language.copyImageAddress : electronMenu.language.copyLinkAddress,
accelerator: "a",
click() {
clipboard.writeText(url);
},
}),
);
}
}
if (popupMenu.items.length > 0) {
popupMenu.popup({});
e.preventDefault();
}
}
})
}
}
module.exports = electronMenu;