00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

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.

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();
});

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) });
});

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
});
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');
  },
});