Electron Adventures: Episode 90: Dock Menu

Electron apps by default are basically web pages with minimal wrapper, but it’s possible to extend them with a lot of OS-specific functionality.

Let’s add OSX Dock menu to our app.

I’ll also finally stop quitting the app when the last window is close…


This content originally appeared on DEV Community and was authored by Tomasz Wegrzanowski

Electron apps by default are basically web pages with minimal wrapper, but it's possible to extend them with a lot of OS-specific functionality.

Let's add OSX Dock menu to our app.

I'll also finally stop quitting the app when the last window is closed. I know pretty much every Electron tutorial does this out of the box for OSX, but this is absolutely NOT the right behavior for every app, and you should not mindlessly copy and paste that code. Most apps have just one window, and if you close that window, that's because your intention is to close the app. Only multi-document app on OSX should really reasonably stay running after their last window is closed.

The only changes will be in index.js, the rest of the app stays identical to what we had before.

Are we on OSX?

The check is very simple, and we could inline in everywhere, but let's create a variable for it:

let isOSX = (process.platform === "darwin")

Start the app

We want to call startApp() when the app is ready. Also when all windows are closed, if we're not on OSX, we still want to just quit the app - all this Dock menu logic will be OSX specific.

app.on("window-all-closed", () => {
  if (!isOSX) {
    app.quit()
  }
})

app.on("ready", startApp)

Setup Dock Menu and reactivation logic

Custom part of our Dock Menu is very simple and static, so we can just pass static data to Menu.buildFromTemplate:

let dockMenu = Menu.buildFromTemplate([
  {
    label: "Open files",
    click() { openFiles() }
  }
])

async function startApp() {
  if (isOSX) {
    app.dock.setMenu(dockMenu)
  }
  await openFiles()
  if (isOSX) {
    app.on("activate", function() {
      if (BrowserWindow.getAllWindows().length === 0) {
        openFiles()
      }
    })
  }
}

startApp() has two pieces of OSX-specific logic. First, we create Dock menu only on OSX, as other systems don't have such concept.

Second, we setup some logic to popup openFiles() dialog if app is reactivated while it has no windows open. We only do this after initial await openFiles() finishes, so we don't popup multiple openFiles dialogs at once.

Everything else:

And everything else is just as before:

let { app, BrowserWindow, dialog, Menu } = require("electron")
let settings = require("electron-settings")

function createWindow(path) {
  let key = `windowState-${path}`
  let windowState = settings.getSync(key) || { width: 1024, height: 768 }

  let qs = new URLSearchParams({ path }).toString();
  let win = new BrowserWindow({
    ...windowState,
    webPreferences: {
      preload: `${__dirname}/preload.js`,
    },
  })

  function saveSettings() {
    windowState = win.getBounds()
    console.log("SAVING", path, windowState)
    settings.setSync(key, windowState)
  }

  win.on("resize", saveSettings)
  win.on("move", saveSettings)
  win.on("close", saveSettings)

  win.loadURL(`http://localhost:5000/?${qs}`)
}

async function openFiles() {
  let { canceled, filePaths } = await dialog.showOpenDialog({
    properties: ["openFile", "multiSelections", "showHiddenFiles"],
    filters: [
      { name: "CSV files", extensions: ["csv"] },
      { name: "All Files", extensions: ["*"] }
    ],
    message: "Select a CSV file to open",
    defaultPath: `${__dirname}/samples`,
  })
  if (canceled && !isOSX) {
    app.quit()
  }
  for (let path of filePaths) {
    createWindow(path)
  }
}

One thing to note is that it's possible to open the same document multiple times. This is generally a good thing, as user might want to view different portions of the same document in multiple windows. However as our saved windows sizes and positions are keyed by document path, it is currently not deterministic which size and position will be restored if user closes it all and tries to reopen it later. Even in such cases, it's still reasonable behavior.

Results

Here's the Dock menu if a few windows are open:

Episode 90 Screenshot

In the next episode, we'll see if we can integrate native file drag and drop.

As usual, all the code for the episode is here.


This content originally appeared on DEV Community and was authored by Tomasz Wegrzanowski


Print Share Comment Cite Upload Translate Updates
APA

Tomasz Wegrzanowski | Sciencx (2021-11-09T01:40:17+00:00) Electron Adventures: Episode 90: Dock Menu. Retrieved from https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/

MLA
" » Electron Adventures: Episode 90: Dock Menu." Tomasz Wegrzanowski | Sciencx - Tuesday November 9, 2021, https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/
HARVARD
Tomasz Wegrzanowski | Sciencx Tuesday November 9, 2021 » Electron Adventures: Episode 90: Dock Menu., viewed ,<https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/>
VANCOUVER
Tomasz Wegrzanowski | Sciencx - » Electron Adventures: Episode 90: Dock Menu. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/
CHICAGO
" » Electron Adventures: Episode 90: Dock Menu." Tomasz Wegrzanowski | Sciencx - Accessed . https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/
IEEE
" » Electron Adventures: Episode 90: Dock Menu." Tomasz Wegrzanowski | Sciencx [Online]. Available: https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/. [Accessed: ]
rf:citation
» Electron Adventures: Episode 90: Dock Menu | Tomasz Wegrzanowski | Sciencx | https://www.scien.cx/2021/11/09/electron-adventures-episode-90-dock-menu/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.