How to change native menu of electron-quick-start example app - javascript

The electron app open with the same default menu that appear in the electron-quick-start example app and how to change it?
Also tried the menu example on the docs but nothing changes.
when I hide the menu with mainWindow.setMenu(null); the menu is gone but still can't init the new menu
any ideas?
platform: windows 7
electron ver: 0.36.4
ref files:
package.json:
{
"name": "electric_timer",
"version": "0.1.0",
"description": "a Time sheet & project managment",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "none"
},
"author": "Eyal Ron",
"license": "MIT"
}
app.js:
var app = require('app');
var BrowserWindow = require('browser-window');
app.on('ready', function (){
var mainWindow = new BrowserWindow({
width: 800,
height: 600
});
mainWindow.setMenu(null);
mainWindow.loadUrl('file://' + __dirname + '/main.html');
});
main.js:
var remote = require('remote');
var Menu = remote.require('menu');
var menu = Menu.buildFromTemplate([
{
label: 'Electron',
submenu: [
{
label: 'Prefs',
click: function(){
alert('hello menu');
}
}
]
}
]);
Menu.setApplicationMenu(menu);
main.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>electron test</title>
</head>
<body>
<h1>hello world</h1>
<script>requier('./main.js')</script>
</body>
</html>

Electron's 'default_app' sets the menu; if you want to avoid this, you need Electron to start your app directly not via the default app (note: if you start your app with something like electron . you actually start the default app).
Electron looks in its resource folder for 'app', 'app.asar' or 'default_app', so in order to start your app directly you need to either copy or link it into Electron's resource folder.
Regardless of how you start your app, you can set your menu using Menu.setApplicationMenu -- you can do it in the main process, you don't need to do it in the Renderer like in your example. Incidentally, there is a typo in your main.html (requier instead of require) so if that's your actual code it would indicate that your main.js does not run at all.

Put your logic to customise the menu into your app('ready') event callback. Give try to following code example
const {app, BrowserWindow, Menu} = require('electron');
let mainWindow;
let menuTemplate = [
{
label: "Window Manager",
submenu: [
{ label: "create New" }
]
},
{
label : "View",
submenu : [
{ role : "reload" },
{ label : "custom reload" }
]
}
];
function appInit () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600})
// and load the main.html of the app.
mainWindow.loadFile('main.html')
let menu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menu);
}
app.on('ready', () => {
appInit();
})

It looks like the electron Menu and MenuItem objects are set up to be immutable.
This means if you want to modify them, you have to create new objects and use that instead. This is what my code does for this, to hide the help menu and developer tools:
// main.js
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
...
let defaultMenu = Menu.getApplicationMenu()
let newMenu = new Menu();
defaultMenu.items
.filter(x => x.role != 'help')
.forEach(x => {
if(x.role == 'viewmenu' && process.env.NODE_ENV == 'production') {
let newSubmenu = new Menu();
x.submenu.items.filter(y => y.role != 'toggledevtools').forEach(y => newSubmenu.append(y));
x.submenu = newSubmenu;
newMenu.append(
new MenuItem({
type: x.type,
label: x.label,
submenu: newSubmenu
})
);
} else {
newMenu.append(x);
}
})
Menu.setApplicationMenu(newMenu);
...
})
}
app.on('ready', createWindow)

Where is Electron in your app? Your package.json file should look like this:
{
"name": "todos",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"electron": "electron ."
},
"author":
"Who Cares <email#example.com> (https://doesntmatter.com/)",
"license": "MIT",
"dependencies": {
"electron": "3.0.8"
}
}
Your Electron side will look like this:
const electron = require('electron');
const { app, BrowserWindow, Menu } = electron;
let mainWindow;
app.on('ready', () => {
mainWindow = new BrowserWindow({});
mainWindow.loadURL(`file://${__dirname}/main.html`);
const mainMenu = Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(mainMenu);
});
const menuTemplate = [
{
label: 'File'
}
];
Even with fixing up the syntax you will still run into the problem of having taken over the default Electron menu and its key binds. You are saying you are going to add your own custom menu and keybinds, which in production if that is your goal then fine, but it sounds like you have lost functionality that you want to maintain.
You could fix it like this:
const menuTemplate = [
{
label: 'File',
submenu: [{ label: 'New Todo' }]
}
];

Related

Electron: Unable to load preload script: Resources/app.asar/src/preload.js

I have an electron app that builds and runs in development, but when packaging the app with electron-builder, the preload script is not packaged in the right location.
This is a well documented issue and there are very similar questions here and here for example, but none of the replies or solutions are working in my case.
From my electron.js file:
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(app.getAppPath(), 'src/preload.js'),
contextIsolation: true,
},
});
// In production, set the initial browser path to the local bundle generated
// by the Create React App build process.
// In development, set it to localhost to allow live/hot-reloading.
const appURL = app.isPackaged
? url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true,
})
: 'http://localhost:3000';
mainWindow.loadURL(appURL);
mainWindow.webContents.openDevTools();
}
My preload script:
const { contextBridge, shell } = require('electron')
contextBridge.exposeInMainWorld(
'electron',
{
openBrowserWindow: (url) => shell.openExternal(url)
}
)
And my Electron app package.json:
"build": {
"extends": null,
"appId": "com.app",
"productName": "App",
"directories": {
"output": "dist"
},
"mac": {
"target": {
"target": "pkg",
"arch": [
"universal"
]
},
"darkModeSupport": "true",
"extendInfo": "app"
},
"pkg": {
"installLocation": "/Applications",
"overwriteAction": "upgrade"
},
"files": [
"**",
"../app/src/*",
"src/preload.js"
],
"extraResources": [
"../app/src/*",
"src/preload.js"
],
"extraFiles": [
"../app/src/*",
"src/preload.js"
]
}
Above I have tried to make sure the "src/preload.js" file is copied over in different ways, but I still get the error:
Unable to load preload script: ...app/Contents/Resources/app.asar/src/preload.js
Error: Cannot find module '...app/Contents/Resources/app.asar/src/preload.js'
The preload script is in fact copied over, but it is not part of the app.asar file. It is copied in to a src folder outside of the Resources folder which contains the app.asar file:
How do I correctly configure electron-builder so this file is in the right location and can be accessed at package runtime?
If you do:
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.resolve(app.getAppPath(), 'preload.js'),
contextIsolation: true,
},
});
Does it works ? (worked for me with electron-webpack and electron-builder)
preload: path.join(app.getAppPath(), 'src/preload.js'),
As you are not packaging the preload.js into the app package file (asar default), this won't work like this. app.getAppPath() will indicate the app package file(or directory, in case you are setting asar as false)
Your code is indicating /xxx.app/Contents/Resources/app.asar/src/preload.js or /xxx.app/Contents/Resources/app/src/preload.js
Your preload script file is not there but in the 2nd parent's directory.
So here is the correct path in your case,
path.join(app.getAppPath(), '..', '..', 'src', 'preload.js');
First, add console logs for testing.
console.log({dirname: __dirname})
console.log({getAppPath: app.getAppPath()})
console.log({resourcesPath: process.resourcesPath})
const mainWindow = new BrowserWindow({ ... })
Second, you have to add contextIsolation: true.
If you are using electron-builder and for some reason you cannot add contextIsolation: true you can use this workaround:
package.json
"build": {
...
"extraResources": [
...
"app/preload.js" // <---- add your path
],
}
electron.js
const preloadPath =
process.env.NODE_ENV === 'development'
? path.join(__dirname, '../preload.js') // <---- add your path
: path.join(process.resourcesPath, '/app/preload.js'); // <---- add your path
const mainWindow = new BrowserWindow({
...
webPreferences: {
contextIsolation: false,
preload: preloadPath,
...
}
})
What is path.join(process.resourcesPath, '/app/preload.js') ?
After building your app you can find your extra resources here
C:\Users\<user>\AppData\Local\Programs\<app>\resources - for Windows.
For MacOS you can right click on your app and click on Show Package Contents > Resources

Electron app opening multiple windows or processes in spectron test

My electron app works as expected but it keeps on opening new windows when I run spectron test that tests for number of windows opened.
Electron version - v8.0.2 , "spectron": "^10.0.1" . I am not sure how to check exact version of spectron.
I am just running a small demo, below I will give code snippet
Note: I am running the spectron test pointing to .exe file generated by electron-packager.
Does Anyone have an idea what is the issue if possible how to solve it?
main.js
const { app, BrowserWindow } = require('electron')
function createWindow () {
let win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
win.loadFile('index.html')
}
app.whenReady().then(createWindow)
index.js
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
test.js
const assert = require('assert');
const path = require('path');
const Application = require('spectron').Application;
const electronPath = require('electron');
const app = new Application({
path: 'C:/demoElectronApp/winx64/demoelectronapp-win32-x64/demoelectronapp.exe',
});
describe('client_settings_app', function () {
this.timeout(10000);
beforeEach(() => {
return app.start();
});
it('shows only one initial window', async () => {
const count = await app.client.getWindowCount();
return assert.equal(count, 1);
});
})
package.json
{
"name": "demoelectronapp",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"electronpackage": "electron-packager . --out winx64"
},
"author": "",
"license": "ISC",
"dependencies": {
"path": "^0.12.7"
},
"devDependencies": {
"electron": "^8.2.2",
"electron-packager": "^14.2.1",
"assert": "^2.0.0",
"mocha": "^7.1.1",
"spectron": "^10.0.1"
}
}
Okay, I was having the same issue. And solved by setting remote debugging port.
chromeDriverArgs: ['remote-debugging-port=9222']
Full test code:
const Application = require('spectron').Application
const assert = require('assert')
const electronPath = require('electron') // Require Electron from the binaries included in node_modules.
const path = require('path')
describe('Application launch', function () {
this.timeout(10000)
beforeEach(function () {
this.app = new Application({
// Your electron path can be any binary
// i.e for OSX an example path could be '/Applications/MyApp.app/Contents/MacOS/MyApp'
// But for the sake of the example we fetch it from our node_modules.
path: path.join(__dirname, '..', 'node_modules', '.bin', 'electron' + (process.platform === 'win32' ? '.cmd' : '')),
// Assuming you have the following directory structure
// |__ my project
// |__ ...
// |__ main.js
// |__ package.json
// |__ index.html
// |__ ...
// |__ test
// |__ spec.js <- You are here! ~ Well you should be.
// The following line tells spectron to look and use the main.js file
// and the package.json located 1 level above.
args: [path.join(__dirname, '..')],
env: {
ELECTRON_ENABLE_LOGGING: true,
ELECTRON_ENABLE_STACK_DUMPING: true,
NODE_ENV: 'test'
},
waitTimeout: 10e3,
requireName: 'electronRequire',
chromeDriverLogPath: '../chromedriverlog.txt',
chromeDriverArgs: ['remote-debugging-port=9222']
})
return this.app.start()
})
afterEach(function () {
if (this.app && this.app.isRunning()) {
return this.app.stop()
}
})
it('shows an initial window', function () {
return this.app.client.getWindowCount().then(function (count) {
assert.equal(count, 1)
// Please note that getWindowCount() will return 2 if `dev tools` are opened.
// assert.equal(count, 2)
})
})
})
I was having a similar issue, and changed the version of the packages I was working with.
This page has the version map:
https://github.com/electron-userland/spectron#version-map
It seems like this isn't your problem byt may help others.
I FINALLY found a way to fix this that worked for me. I found it in a comment by #wburgess-invision on this gitHub thread here: https://github.com/electron-userland/spectron/issues/60
Navigate to node_modules -> spectron -> lib -> launcher.js
after the line "const args = appArgs.concat(chromeArgs);" add a new line and copy and paste this: args.splice(args.indexOf('--enable-logging'), 1)
npm run build
To quote the thread: "I noticed that it was happening because of the --enable-logging parameter being passed in. So I made a modified version of launcher.js which purposely didn't include --enable-logging and it worked fine for us. I couldn't find where the spectron launcher was managing to pick up the --enable-logging flag from as I thought a better solution would have been just not providing it to launcher.js in the first place but I couldn't find out so I just went with the solution that worked for now. My assumption was that the --enable-logging flag was being picked up somewhere inside of webdriverio when the client is initialized and thus calls launcher.bat but I couldn't find out where."

How to receive data in Electron app from protocol link

I'm making a game client and I have it where you can launch the game from the browser like 'mygame://whatever'. I'm doing some debugging and I want it to show 'Received this data: whatever'. It does launch the app but it just shows undefined in the data box. How do I fix this?
main.js:
const {app, BrowserWindow} = require('electron');
let mainWindow;
function createWindow () {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
mainWindow.loadFile('index.html');
}
app.on('ready', createWindow);
var link;
app.on('open-url', function (event, data) {
event.preventDefault();
link = data;
});
app.setAsDefaultProtocolClient('mygame');
// Export so you can access it from the renderer thread
module.exports.getLink = () => link;
index.html:
<!DOCTYPE html>
<html>
<body>
<p>Received this data <input id="data"></p>
<script>
const {getLink} = require('electron').remote.require('./main.js');
document.querySelector('#data').value = getLink();
</script>
</body>
</html>
package.json:
{
"name": "mygame",
"version": "1.0.0-dev",
"description": "Development copy.",
"main": "main.js",
"scripts": {
"start": "electron .",
"dist": "electron-builder"
},
"author": "Me",
"build": {
"protocols": {
"name": "mygame-protocol",
"schemes": [
"mygame"
]
}
},
"devDependencies": {
"electron": "^6.0.9",
"electron-builder": "^21.2.0"
}
}
All help is appreciated!
this code work only for iOS
app.on('open-url', function (event, data) {
event.preventDefault();
link = data;
});
In win32 you must use that code
process.argv[1]
so you can add that code in createWindow() like that:
function createWindow () {
// Crea la finestra del browser
let win = new BrowserWindow({
width: 800,
height: 600,
});
//other stuff
link = process.argv[1];
}
Resources that might be useful
electron url scheme “open-url” event

Cannot use require in a separate js file in Electron

I have a very simple Electron app, using version 5.0.1.
Here is my index.html file:
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Webgl</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/104/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="./initialization.js"></script>
<link rel="stylesheet" type="text/css" href="application.css">
</head>
<body>
<script>
initialization();
</script>
</html>
Then my main.js file:
const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')
let win
function createWindow () {
// Create the browser window.
win = new BrowserWindow({ width: 1280,
height: 720,
nodeIntegration: true,
resizable: false,
maximizable: false })
// and load the index.html of the app.
win.loadFile('index.html')
// Open the DevTools.
win.webContents.openDevTools()
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (win === null) {
createWindow()
}
})
my package.json file:
{
"name": "estimation",
"version": "1.0.0",
"description": "estimation app",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^5.0.1"
}
}
Then my inittialization.js file that contains the initialization() method and const fs = require('fs');
const fs = require('fs');
function initialization(){
}
Now I have asked the same question in multiple places, I have tried multiple solutions, nothing works. I am wondering if this is an Electron bug at this stage.
The error I can't get rid off and I keep getting whatever I do is this Uncaught ReferenceError: require is not defined
I simply want to use require in another JS file. Why is node.js or electron not picking this up ?
Place the nodeIntegration inside webPreferences attribute
{ width: 1280,
height: 720,
webPreferences : { nodeIntegration: true },
resizable: false,
maximizable: false
}

Electron not loading web application with full functionalities

I tried loading a web application in electron using window.loadurl and as webview in html. Application is displaying, but with different errors like:
$ jquery not defined
Uncaught TypeError: $(...).daterangepicker is not a function
Uncaught TypeError: Cannot read property 'getContext' of undefined
I tried different methods and finally get rid off '$ jquery not defined' error.
Why electron is not acting as a browser. This application is working fine on all browsers.
How can I load this web application to my electron with functionalities.
My web application is :
www.mcgeoautomation.com
My index.js file is:
const electron = require('electron');
const app = electron.app;
var path=require('path');
const BrowserWindow = electron.BrowserWindow;
var mainWindow;
app.on('ready',function(){
mainWindow = new BrowserWindow({
width: 1024,
height: 768,
backgroundColor: '#2e2c29',
show:false,
});
mainWindow.loadURL(`file://${__dirname}/webView.html`);
mainWindow.maximize(true);
// mainWindow.setMenu(null);
mainWindow.once('ready-to-show',()=>{
mainWindow.show()
})
mainWindow.on('close', (e)=>{
app.quit();
});
});
package.json file:
`{
"name": "crushmate",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "electron ."
},
"author": "",
"license": "ISC",
"dependencies": {
"electron": "^1.7.9",
"jquery": "^3.2.1"
},
"devDependencies": {
"electron-prebuilt": "^1.4.13"
}
}`
Please help...
Regards...
Electron doesn't handle jQuery the same as a regular browser does. You have to essentially inject it into the webview. Can't test this right now but should get you on the way to it working.
index.html
<!DOCTYPE html>
<html>
<head>
<title>jQuery injection into webview preload</title>
</head>
<body style="overflow:hidden;">
<webview id="webview" preload="./preload.js" src="http://www.mcgeoautomation.com" style="position:absolute;width:100%;height:100%;"></webview>
<script>
// need to have a script tag make webview work even if you don't plan to use it...
</script>
</body>
</html>
preload.js
window.onload = function() {
var script = document.createElement("script");
script.src = "https://code.jquery.com/jquery-2.1.4.min.js";
document.body.appendChild(script);
};
I ran into the same issue and deativating nodeIntegration solved it for me.
Just add following code when creating a BrowserWindow:
webPreferences: {
nodeIntegration: false
}
(The used electron version is "11.2.0")

Categories

Resources