@laserware/hoverboard
Version:
Better context menus for Electron.
128 lines (126 loc) • 3.96 kB
JavaScript
import { ipcMain, BrowserWindow, clipboard, shell, nativeImage, Menu } from 'electron';
// src/main/configureContextMenus.ts
function createCustomContextMenu(id, template) {
const contextMenu = Menu.buildFromTemplate(template);
return Object.assign(contextMenu, { id });
}
function configureContextMenus(options) {
const contextMenus = /* @__PURE__ */ new Map();
const closeContextMenu = (menuId, window) => {
contextMenus.get(menuId)?.closePopup(window);
contextMenus.delete(menuId);
};
const handleShowContextMenu = (event, request) => {
const browserWindow = BrowserWindow.fromWebContents(event.sender);
if (browserWindow === null) {
return;
}
const { menuId, position, template, linkURL } = request;
return new Promise((resolve) => {
closeContextMenu(menuId, browserWindow);
for (const item of walkMenuTemplate(template)) {
item.icon = getIconForMenuItem(item);
if (item.type !== "separator" && item.role === void 0) {
item.click = (menuItem, window, event2) => {
if (item.id === void 0) {
throw new Error("Clickable item must have an ID");
}
resolve({
menuId,
menuItemId: item.id,
event: event2
});
};
}
}
const zoomFactor = browserWindow.webContents.getZoomFactor();
const x = Math.floor(position.x * zoomFactor);
const y = Math.floor(position.y * zoomFactor);
if (linkURL !== void 0) {
template.push(
{ type: "separator" },
{
label: "Copy Link",
type: "normal",
click: () => {
void clipboard.writeText(linkURL, "clipboard");
}
},
{
label: "Open Link",
type: "normal",
click: () => {
void shell.openExternal(linkURL);
}
}
);
}
if (options.inspectElement) {
template.push(
{ type: "separator" },
{
label: "Inspect Element",
type: "normal",
click: () => {
browserWindow.webContents?.inspectElement(x, y);
}
}
);
}
const contextMenu = createCustomContextMenu(menuId, template);
contextMenus.set(menuId, contextMenu);
contextMenu.popup({
window: browserWindow,
x,
y,
callback() {
contextMenus.delete(menuId);
resolve({
menuId,
menuItemId: null,
event: {}
});
}
});
});
};
const handleHideContextMenu = (event, menuId) => {
const browserWindow = BrowserWindow.fromWebContents(event.sender);
if (browserWindow === null) {
return;
}
closeContextMenu(menuId, browserWindow);
};
ipcMain.handle("hoverboard/contextMenu/show" /* ForShowContextMenu */, handleShowContextMenu);
ipcMain.handle("hoverboard/contextMenu/hide" /* ForHideContextMenu */, handleHideContextMenu);
return {
dispose() {
ipcMain.removeHandler("hoverboard/contextMenu/show" /* ForShowContextMenu */);
ipcMain.removeHandler("hoverboard/contextMenu/hide" /* ForHideContextMenu */);
}
};
}
function getIconForMenuItem(menuItem) {
if (typeof menuItem.icon !== "string") {
return void 0;
}
let image = nativeImage.createFromPath(menuItem.icon);
if (image.isEmpty()) {
image = nativeImage.createFromDataURL(menuItem.icon);
}
return image.resize({ width: 16, height: 16, quality: "best" });
}
function* walkMenuTemplate(template) {
function* recurse(items) {
for (const item of items) {
yield item;
if (Array.isArray(item.submenu)) {
yield* recurse(item.submenu);
}
}
}
yield* recurse(template);
}
export { configureContextMenus };
//# sourceMappingURL=main.mjs.map
//# sourceMappingURL=main.mjs.map