Undefined template constant in Electron - javascript

I'm in the process of finishing up my first app on Electron, i'm a Junior Web Developer, so please excuse me if it's a simple mistake or you spot something you think can be done better. But basically, I'm building a basic menu on macOS so I can have Copy / Paste functionality after packaging. Now i've followed the documentation from https://github.com/electron/electron/blob/master/docs/api/menu.md, made a few tweaks to fit my needs but seem to be having a problem when running, the error being:
Uncaught Exception:
TypeError: Cannot read property 'buildFromTemplate' of undefined
at EventEmitter.createWindow (/Users/Jay/Desktop/click_palette_release/app/main.js:73:22)
at emitOne (events.js:101:20)
at EventEmitter.emit (events.js:188:7)
This to me would suggest that 'template' isn't defined? However I define it at the top on line 70 with const. What am I missing here? Been scratching my head at it for some time now.
const template = [
{
label: 'Edit',
submenu: [
{
role: 'copy'
},
{
role: 'paste'
},
]
}];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
Line 73 being const menu = Menu.buildFromTemplate(template);
Thanks in advance!
Full code:
const electron = require('electron');
const {app} = electron;
const {BrowserWindow} = electron;
const Configstore = require('configstore');
const pkg = require(__dirname + '/init.json');
const sysconf = new Configstore(pkg.name);
var Menu = require("electron").menu;
let mainWindow;
function createWindow(){
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
if (sysconf.get('bounds')){
var bounds = sysconf.get('bounds');
} else {
var bounds = {'x':'', 'y':'', 'width':'400', 'height':'125'}
}
// Create the browser window.
mainWindow = new BrowserWindow({
x: bounds.x,
y: bounds.y,
width: 400,
height: 90,
//'titleBarStyle': 'hidden',
title: 'ClickPalette',
backgroundColor: '#fff',
frame: false
});
mainWindow.setResizable(false);
mainWindow.setAlwaysOnTop(true);
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.setMenu(null);
//mainWindow.webContents.openDevTools();
mainWindow.on('close', function(e) {
var bounds = mainWindow.getBounds();
sysconf.set({'bounds' : bounds});
});
// Emitted when the window is closed.
mainWindow.on('closed', function() {
mainWindow = null;
});
//Settings / Manager
var manageWindow = new BrowserWindow({
width: 400,
height: 400,
show: false
});
manageWindow.loadURL('file://' + __dirname + '/manage.html');
//manageWindow.webContents.openDevTools();
const template = [
{
label: 'Edit',
submenu: [
{
role: 'copy'
},
{
role: 'paste'
},
]
}];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
};
// Load mainWindow
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit();
}
});
//Show window
app.on('activate', function (e) {
if (mainWindow === null) {
createWindow();
}
});
RESOLVED
I was using const Menu = require('electron').menu; but the M in menu should have been uppercase: const Menu = require('electron').Menu;

Related

Open new window from Menu

When trying to open the window from the menu, an error like this comes up: "Attemping to call a function in a renderer window that has been closed or released", but the other windows are called without any problem.
const ventana = document.getElementById("ventana");
const contrasena = document.getElementById("contra");
const remote = require("electron").remote;
const Menu = remote.Menu;
const BrowserWindow = remote.BrowserWindow;
const url = require("url");
const path = require("path");
let secundario
let recuperaVentana
let add
ventana.addEventListener("click", () => {
var usuario = document.getElementById("user").value;
var pass = document.getElementById("pass").value;
if(usuario != "" & pass != ""){
createBrowserWindow();
} else {
alert("No ha llenado los campos");
}
});
contrasena.addEventListener("click", () => {
recuperarBrowserWindow();
})
function createBrowserWindow() {
secundario = new BrowserWindow({
height: 600,
width: 800
});
secundario.loadURL(url.format({
pathname: path.join(__dirname, "./prefs.html"),
protocol: "file",
slashes: true
}));
//secundario.webContents.openDevTools();
//menu
const menuSec = Menu.buildFromTemplate(templateMenu);
Menu.setApplicationMenu(menuSec);
cerrar();
}
function recuperarBrowserWindow(){
recuperaVentana = new BrowserWindow ({
title: "Recuperar"
})
recuperaVentana.loadURL(url.format({
pathname: path.join(__dirname, "./recuperar.html"),
protocol: "file",
slashes: true
}))
recuperaVentana.setMenu(null);
}
//cerrando ventana
function cerrar(){
window.close();
}
//creando menus
const templateMenu = [
{
label: "Archivo",
submenu: [
{
label: "Nuevo",
accelerator: "Ctrl+N",
click(){
addBrowserWindow();
}
},
{
label: "Abrir",
accelerator: "Ctrl+O"
},
{
label:"Guardar",
accelerator:"Ctrl+G"
},
{
type: "separator"
},
{
label:"Salir"
}
]
},
{
label: "Ayuda"
}
];
function addBrowserWindow() {
add = new BrowserWindow({
title: "Agregar"
})
add.loadURL(url.format({
pathname: path.join(__dirname, "./agregar.html"),
protocol: "file",
slashes: true
}))
}
When trying to call the function "addBrowserWindow()" the above mentioned error is shown
This is a fairly concise version of code that creates a second window on selecting a submenu:
const electron = require('electron')
const { app, BrowserWindow, Menu } = electron
let mainWindow
let secondWindow
app.on('ready', () => {
console.log('Starting Node version: ' + process.version)
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: true,
},
})
mainWindow.loadURL(`file://${__dirname}/main.html`)
mainWindow.on('closed', () => app.quit())
const mainMenu = Menu.buildFromTemplate(menuTemplate)
Menu.setApplicationMenu(mainMenu)
})
function createSecondWindow() {
secondWindow = new BrowserWindow({
width: 300,
height: 200,
title: 'Add New Todo',
})
secondWindow.loadURL(`file://${__dirname}/add.html`)
}
const menuTemplate = [
{
label: 'File',
submenu: [
{
label: 'New ToDo',
click() {
createSecondWindow()
},
},
{
label: 'Quit',
accelerator: process.platform === 'darwin' ? 'Command+Q' : 'Ctrl+Q',
click() {
app.quit()
},
},
],
},
]
if (process.platform === 'darwin') {
menuTemplate.unshift({})
}
Note that by default when you close the main window and the second window will still be present - which is weird behaviour rarely needed. The solution to that is to ensure you call app.exit() when the main window is closed.

How do i make a separate menu for a specific window in electron?

I am working on an about this app window on Windows and I want to make a custom menu bar for my about window. Since I already have a custom menu is there a way I can create another one and apply it only to that specific window?
Side note:
Here is my code for the new window that is supposed to stop it from being adjusted and going into full screen, but for some reason the minimize and enlarge button still work.
app.on('ready', createWindow);
electron.app.on('ready', () => {
//Triger update check
if (!isDev) {
autoUpdater.checkForUpdates();
}
})
function createWindow(){
//create brower window
win = new BrowserWindow({
backgroundColor: '#2e2c29',
width: 800,
height: 600,
//transparent: true,
frame: false,
titleBarStyle: 'hidden',
backgroundColor: '#0000',
webPreferences: {
nodeIntegration: true
}
});
//Quit when all windows are closed
app.on('window-all-closed', () => {
app.quit()
})
app.once('ready', function() {
const template = [
{
label: 'File',
submenu: [
{
label: 'About Hubris',
click: () =>
openAboutWindow()
},
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
},
{
label: 'View',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
//here is the code for the about window
var newWindow = null
function openAboutWindow() {
if (newWindow) {
newWindow.focus()
return
}
newWindow = new BrowserWindow({
height: 439,
resizable: false,
width: 599,
title: 'About Hubris',
minimizable: false,
fullscreenable: false,
frame: false,
titleBarStyle: 'hidden',
})
newWindow.loadURL('file://' + __dirname + '/about-this-app.html')
newWindow.on('closed', function() {
newWindow = null
})
}
});
You can switch menus on the fly. I have an app with 'editor' and 'presentation' modes. I create and store a menu for each mode (they have different menu items):
let editorMenu = Menu.buildFromTemplate(menuTemplate);
and subscribe to the relevant window events (focus, blur, etc). Then when a window gets focus
Menu.setApplicationMenu(editorMenu);
To do this, you have to import menu from electron in at the top of our main.js file:
// From
const {app, BrowserWindow} = require('electron')
// To
const {app, BrowserWindow, Menu} = require('electron').
Then, near the bottom of our createWindow() function, we add:
function createWindow () {
// some code here removed for brevity
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'Adjust Notification Value'},
{label:'CoinMarketCap'},
{label:'Exit'}
]
}
])
Menu.setApplicationMenu(menu);
}
Next, we reference Menu.buildFromTemplate([{}]), which is where our menu is actually defined and built, within a series of arrays and objects.
The "label" represents the name you want your menu to display so put what you like.
The "submenu" property is an array of objects, with each object defining the actual menu items displayed when the label is clicked.
Finally, use .setApplicationMenu to set the menu. If you save the project, and run npm start in the console, you will see the menu with it's items (array) being displayed but if your click on them nothing happens.
You can change this by going back to our main.js, add the following code to make our Exit button close the application:
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'Adjust Notification Value'},
{label:'CoinMarketCap'},
{
label:'Exit',
click() {
app.quit()
}
}
]
}
])
So, to make a menu item clickable, we simply add a comma after the label value, and reference "click() { }"
In this case, we're calling app.quit()" when the Exit submenu item is clicked. Give it a try by running npm start in the console and click Exit.
That's it!

How to enable right-click with Electron BrowserWindow and BrowserView?

I have a BrowserView inside a BrowserWindow (I need both indeed):
const { app, BrowserWindow, BrowserView } = require('electron');
app.on('ready', () => {
browserWindow = new BrowserWindow({ width: 800, height: 500, frame: false });
bv = new BrowserView({ webPreferences: { nodeIntegration: false }});
bv.setBounds({ x: 0, y: 30, width: 800, height: 470});
bv.webContents.loadURL('https://old.reddit.com');
browserWindow.setBrowserView(bv);
});
Doing a right-click on web pages doesn't do anything. How to enable right-click to have "Back", "Forward", "Reload", "Copy", "Paste", etc. as usual with Chrome?
Electron has some sample menus up on their docs located at https://electronjs.org/docs/api/menu
// Importing this adds a right-click menu with 'Inspect Element' option
const remote = require('remote')
const Menu = remote.require('menu')
const MenuItem = remote.require('menu-item')
let rightClickPosition = null
const menu = new Menu()
const menuItem = new MenuItem({
label: 'Inspect Element',
click: () => {
remote.getCurrentWindow().inspectElement(rightClickPosition.x, rightClickPosition.y)
}
})
menu.append(menuItem)
window.addEventListener('contextmenu', (e) => {
e.preventDefault()
rightClickPosition = {x: e.x, y: e.y}
menu.popup(remote.getCurrentWindow())
}, false)
Following this template you could set up custom roles like Back, Forward, Reload, etc. using custom javascript like this:
Back
const backMenuItem = new MenuItem({
label: 'Back',
click: () => {
window.history.back();
}
})
menu.append(backMenuItem)
Forward
const forwardMenuItem = new MenuItem({
label: 'Forward',
click: () => {
window.history.forward();
}
})
menu.append(forwardMenuItem)

Open a new window to display a html file using a menu click - Electron

I'm new to Electron and JavaScript. I'm building an Electron app. I know how to open a URL in a browser via clicking an item in native menu(by studying the documentation), but I need to open a html file in another Electron window using an Electron's native menu click. If I have my menu structure like below, how can I achieve this? Please help.
const {Menu} = require('electron');
const nativeMenus = [
{
label: 'About',
submenu: [
{
label: 'About',
click () {--- code to open about.html file in another electron window}
}
]
}
]
const menu = Menu.buildFromTemplate(nativeMenus);
Menu.setApplicationMenu(menu);
If it is all in the main.js just create a function to create a new window and then call that on menu item click.
const { Menu } = require('electron')
const ipc = require('electron').ipcRenderer
const nativeMenus = [
{
label: 'About',
submenu: [
{
label: 'About',
click() {
openAboutWindow()
}
}
]
}
]
const menu = Menu.buildFromTemplate(nativeMenus)
Menu.setApplicationMenu(menu)
var newWindow = null
function openAboutWindow() {
if (newWindow) {
newWindow.focus()
return
}
newWindow = new BrowserWindow({
height: 185,
resizable: false,
width: 270,
title: '',
minimizable: false,
fullscreenable: false
})
newWindow.loadURL('file://' + __dirname + '/views/about.html')
newWindow.on('closed', function() {
newWindow = null
})
}
Let me know if this works for you.
You stored your BrowserWindow instance in a variable, for the sake of this answer I am gonna suppose it's win. user7252292 did provide you with a good answer. But if you need another window then you will have to create another function for the same purpose. I will make a function for creating modals. They are basically windows that need a parent window and you cannot respond to the parent window until the modal is closed.
const createModal = (htmlFile, parentWindow, width, height) => {
let modal = new BrowserWindow({
width: width,
height: height,
modal: true,
parent: parentWindow,
webPreferences: {
nodeIntegration: true
}
})
modal.loadFile(htmlFile)
return modal;
}
const {Menu} = require('electron');
const nativeMenus = [
{
label: 'About',
submenu: [
{
label: 'About',
click () {
createModal("myfile.html",win,600,800); // Win is the browerwindow instance
}
}
]
}
]
const menu = Menu.buildFromTemplate(nativeMenus);
Menu.setApplicationMenu(menu);
Plus, you can store the createModal in a variable and modify the modal because it returns the modal itself.

app.setBadgeCount is not working

app.on('ready', function () {
let self = this;
mainWindow = new BrowserWindow({
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
'node-integration': false,
preload: __dirname + '/vendor/electron_boilerplate/context_menu.js',
});
if (process.platform === 'linux') {
app.getLocale();
mainWindow.setBadgeCount = 5;
}
}
Why can't I use electron.app.setBadgeCount() ?
The first problem is that setBadgeCount is a function, not a property, and the second problem is that it's part of the app module. What you should be doing is:
app.setBadgeCount(5)

Categories

Resources