Menu Contestuali
I menu contestuali (o menu a comparsa) appaiono quando l’utente fa clic con il tasto destro del mouse. Electron permette di creare menu contestuali nativi personalizzati.
Menu Contestuale Base
Dal Main Process
// main.js
const { Menu, ipcMain, BrowserWindow } = require('electron');
ipcMain.on('show-context-menu', (event) => {
const template = [
{
label: 'Taglia',
role: 'cut',
},
{
label: 'Copia',
role: 'copy',
},
{
label: 'Incolla',
role: 'paste',
},
{ type: 'separator' },
{
label: 'Seleziona tutto',
role: 'selectAll',
},
];
const menu = Menu.buildFromTemplate(template);
menu.popup({
window: BrowserWindow.fromWebContents(event.sender),
});
});
Dal Preload e Renderer
// preload.js
contextBridge.exposeInMainWorld('electronAPI', {
showContextMenu: () => ipcRenderer.send('show-context-menu'),
onContextMenuAction: (callback) => {
ipcRenderer.on('context-menu-action', (_event, action) => callback(action));
},
});
// renderer.js
window.addEventListener('contextmenu', (e) => {
e.preventDefault();
window.electronAPI.showContextMenu();
});
Menu Contestuale Dinamico
Crea menu diversi in base al contesto (dove l’utente ha cliccato):
// renderer.js
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
const target = e.target;
let context = 'default';
if (target.closest('.file-item')) {
context = 'file';
} else if (target.closest('.editor')) {
context = 'editor';
} else if (target.closest('img')) {
context = 'image';
}
window.electronAPI.showContextMenu(context);
});
// main.js
ipcMain.on('show-context-menu', (event, context) => {
let template;
switch (context) {
case 'file':
template = [
{ label: 'Apri', click: () => event.sender.send('context-action', 'open') },
{ label: 'Rinomina', click: () => event.sender.send('context-action', 'rename') },
{ type: 'separator' },
{ label: 'Elimina', click: () => event.sender.send('context-action', 'delete') },
];
break;
case 'editor':
template = [
{ role: 'cut', label: 'Taglia' },
{ role: 'copy', label: 'Copia' },
{ role: 'paste', label: 'Incolla' },
{ type: 'separator' },
{ label: 'Formatta', click: () => event.sender.send('context-action', 'format') },
];
break;
case 'image':
template = [
{ label: 'Copia immagine', click: () => event.sender.send('context-action', 'copy-image') },
{ label: 'Salva immagine', click: () => event.sender.send('context-action', 'save-image') },
];
break;
default:
template = [
{ role: 'copy', label: 'Copia' },
{ role: 'paste', label: 'Incolla' },
];
}
const menu = Menu.buildFromTemplate(template);
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) });
});
Menu Contestuale con Dati
Puoi passare dati aggiuntivi al menu contestuale:
// renderer.js
document.querySelectorAll('.file-item').forEach((item) => {
item.addEventListener('contextmenu', (e) => {
e.preventDefault();
const fileData = {
id: item.dataset.id,
name: item.dataset.name,
path: item.dataset.path,
};
window.electronAPI.showFileContextMenu(fileData);
});
});
// main.js
ipcMain.on('show-file-context-menu', (event, fileData) => {
const template = [
{
label: `Apri "${fileData.name}"`,
click: () => {
event.sender.send('context-action', { action: 'open', file: fileData });
},
},
{
label: 'Rinomina',
click: () => {
event.sender.send('context-action', { action: 'rename', file: fileData });
},
},
{ type: 'separator' },
{
label: 'Mostra nel file manager',
click: () => {
const { shell } = require('electron');
shell.showItemInFolder(fileData.path);
},
},
{ type: 'separator' },
{
label: 'Elimina',
click: () => {
event.sender.send('context-action', { action: 'delete', file: fileData });
},
},
];
const menu = Menu.buildFromTemplate(template);
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) });
});
Posizionamento del Menu
Puoi specificare dove deve apparire il menu:
menu.popup({
window: mainWindow,
x: 100, // Coordinata X
y: 200, // Coordinata Y
});
Menu Contestuale con Sottomenu
const template = [
{
label: 'Nuovo',
submenu: [
{ label: 'File', click: () => { /* ... */ } },
{ label: 'Cartella', click: () => { /* ... */ } },
{ type: 'separator' },
{ label: 'Da template...', click: () => { /* ... */ } },
],
},
{ type: 'separator' },
{ role: 'copy', label: 'Copia' },
{ role: 'paste', label: 'Incolla' },
];
Evento di Chiusura del Menu
Puoi sapere quando il menu viene chiuso:
const menu = Menu.buildFromTemplate(template);
menu.popup({
window: mainWindow,
callback: () => {
// Chiamato quando il menu viene chiuso
// (sia per selezione che per annullamento)
console.log('Menu contestuale chiuso');
},
});