My Main.js code is:
let mainWindow = null;
const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()){
mainWindow.restore();
}
mainWindow.show();
mainWindow.focus();
}
});
if (shouldQuit) {
app.quit();
}
This is basically identical to the Electron docs, and to all examples I can find on the web. Has anyone else had this issue? I see on the web a good deal of people saying this code doesn't work for them.
I am building my app using Electron-Builder.
Thank you.
This started working some time ago, and I have since upgraded Electron a few times, so I am forced to assume this was an Electron bug in versions below 1.4.
Countless other experiences on the web that also went unsolved during this time lend credence to this idea.
...
// Force Single Instance Application
const shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (win) {
if (win.isMinimized()) win.restore()
win.focus()
}
})
if (shouldQuit) {
app.quit()
return
}
...
Refs: app.makeSingleInstance(callback): and dominikfiala's comment
Related
Here is a block of code from my application Codey.
src/main.py
// Show window once it has finished initialising
docsWindow.once("ready-to-show", () => {
if (darkMode) {
docsWindow.webContents.send("dark-mode:toggle");
}
if (!isDarwin) {
docsWindow.webContents.send("platform:not-darwin");
}
docsWindow.webContents.send("docs:jump", section);
docsWindow.show();
});
src/docs/renderer.js
window.api.darkMode.toggle.receive(toggleDarkMode);
When darkMode = true, toggleDarkMode is never run.
My application has two different windows - an editor and a docs window. For both windows, on the "ready-to-show" event, "dark-mode:toggle" is sent to the renderer process. However, the docs window fails to run the toggleDarkMode function whilst it works for the editor window.
Note: The application must be packaged using "yarn package" as some features do not work in the dev environment.
Any help will be much appreciated.
(Repo: https://github.com/Liamohara/Codey)
For anyone that's interested. I found a solution to my issue.
src/main.py
// Show window once it has finished initialising
- docsWindow.once("ready-to-show", () => {
+ docsWindow.webContents.once("did-finish-load", () => {
if (darkMode) {
docsWindow.webContents.send("dark-mode:toggle");
}
if (!isDarwin) {
docsWindow.webContents.send("platform:not-darwin");
}
docsWindow.webContents.send("docs:jump", section);
docsWindow.show();
});
In the docs window, there is more HTML content to be renderered than in the editor window. As a result, the DOM takes longer to load and the "ready-to-show" event is emitted before it has finished. Using the "did-finish-load" event, ensures that the API functions are not called before the DOM has finished loading.
So first off, I know about the following question Custom HTML Dialog in Electron already exists. My question expands on this question when some problems came up on the latest version of electron.
So some context:
I actually started a project of mine on like a very old version on Electron(v2.0.5) that I already had cuz I was too lazy to update electron. I got a working dialog class that you could do something like this:
let dialog = new dialog_class("./pages/dialog.html")
dialog.display().then((response) => console.log(response));
However I had to update my version to the current(v9.1.1) so of course my dialog broke, but I can't figure out how/why.
I create my dialog very much like this:
constructor(link){
this.link = link;
this.window = new electron.remote.BrowserWindow({...});
}
display(){
return new Promise((callback)=>{
this.window.loadURL(...);//url.format function in place of ...
this.window.on(`close`, () => {
if (!this.cancelCloseEvent) callback(false);
});
}
}
destroy(){
this.window.closable = true;
this.widow.close();
}
However, when I run this function:
function openDialog(){
let dialog = new dialog_class("./pages/dialog.html")
dialog.display().then((response) => console.log(response));
}
I can open the dialog perfectly, but can only close the dialog once. Like I can open it, close it then open it again but can't close it again. When I try to close it a 2nd time it keeps the dialog open AND throws this:
electron/js2c/renderer_init.js:82 Uncaught TypeError: Object has been destroyed
at BrowserWindow.get (electron/js2c/browser_init.js:125)
at electron/js2c/browser_init.js:233
at IpcMainImpl.<anonymous> (electron/js2c/browser_init.js:233)
at IpcMainImpl.emit (events.js:223)
at WebContents.<anonymous> (electron/js2c/browser_init.js:173)
at WebContents.emit (events.js:223)
I don't know why this happens, as each time I run openDialog it should create a NEW BrowserWindow, so I don't know how it's referencing the old window.
Note: all the code shown here should be enough for my problem. But just in case heres the entire dialog_class: https://pastebin.com/7pAwZJHF
Edit:
Since I'm putting a bounty on this, I wanted people to be able to reproduce the issue. Heres all the code you'll need: https://github.com/Frustrated-Programmer/ElectronBug
However: I still think all the code relevant is still supplied in this question
dialog.js
display(context) {
return new Promise((cb) => {
electron.ipcRenderer.on("callback", (event, val) => {
this._cancelCloseEvent = true;
cb(val);
// this.destroy(); WRONG!!! Remove this and destory your window on test.js which is having this object instance
});
}
...
test.js
dialog.display().then(function(value) {
response.innerText = value;
dialog.destroy();
// dialog = null; unnecessary!
});
Does the Electron application framework have built-in text search?
The quick-start application doesn't provide any apparent search functionality (e.g. using Ctrl-F or from the menu options). I would have expected this to be a BrowserWindow option (or an option of its WebContents), but I don't see anything helpful in the docs.
I know this is an old thread, but might still be relevant for people out there.
Had the same problem, and first fixed by using electron-in-page-search, but this component doesn't work properly with Electron 2 or greater.
Then finally found electron-find resolved my problem. Using with Electron 4.
You just add the component to your project:
npm install electron-find --save
Add a global shortcut in your Electron main process to send an event to the renderer in a ctrl+f:
globalShortcut.register('CommandOrControl+F', () => {
window.webContents.send('on-find');
});
And then you can add this to your page (the renderer process)
const remote = require('electron').remote;
const FindInPage = require('electron-find').FindInPage;
let findInPage = new FindInPage(remote.getCurrentWebContents());
ipcRenderer.on('on-find', (e, args) => {
findInPage.openFindWindow()
})
Hope that helps.
Try webContents.findInPage just added in the latest version.
There is an issue with the solution Robson Hermes offered. globalShortcut is, by definition, global, so the shortcut will be detected even when the app is not focused. This will result in the Ctrl+F shortcut being "stolen" from everywhere else.
I have found no ideal solution (see this issue on the electron repository), but a hacky one can be achieved by doing what Robson said and adding
win.on('focus', () => {
globalShortcut.register('CommandOrControl+F', () => windows.main.send('on-find'))
})
win.on('blur', () => {
globalShortcut.unregister('CommandOrControl+F')
}
Note that as seen here, this is not ideal and can lead to several issues:
Other applications can get a lock on the shortcut when you lose focus, i.e. the shortcut will magically stop working when you switch back to the app later.
Some apps can appear on screen without taking focus (spotlight I believe has this behavior) and during the app's appearance the shortcuts will still be captured by your application.
There's also gonna be those weird one in a thousand situations where somehow you switch focus and the shortcut is not removed.
Instead of using global shortcuts , use Accelerators ( normal Keyboard shortcut )
{
label : 'help',
click : function(){.
electron.shell.openExternal('http://....').
},
accelerator : 'CmdOrCtrl+ Shift + H'
}
The above shown is just an example of How to use accelerator
I have a problem with Cordova's android application based on Angular 5+. I've found that window.history.back() and similar native JS back functions make two problems:
when going back, a page is flashing. It seems like first, all HTML content loaded and after it CSS
In one page on a back action, my layout is broken (screens below)
Orginal view:
After back button:
What's curious - after changing phone orientation all backs to normal.
I've found a solution - instead of using vanilla JS back functions I've created mine using Angular Router:
I've subscribe on router's events and save all routes:
this._subs.push(this._router.events.subscribe((e) => {
if (e instanceof NavigationEnd) {
this._cordovaService.saveRoute(e.url);
}
}));
And if I want back, I use navigateByUrl function:
back(): void {
const lastRoute = this._routingHistory[this._routingHistory.length - 2];
if (lastRoute) {
this._router.navigateByUrl(lastRoute);
this._routingHistory.pop();
}
}
After implementing this functionality for my inApp back buttons all work fine - there is no flashing or breaking layout.
Although, after implemented this function for my physical back button, the error is the same - layout breaking or flashing. Below my implementation:
Service:
this.deviceReady = Observable.fromEvent(document, 'deviceready').publishReplay(1);
(this.deviceReady as ConnectableObservable<Event>).connect();
this.restore = Observable.fromEvent(document, 'resume').publishReplay();
(this.restore as ConnectableObservable<Event>).connect();
this.backbutton = Observable.fromEvent(document, 'backbutton').publishReplay();
(this.backbutton as ConnectableObservable<Event>).connect();
Using it:
this._subs.push(this._cordovaService.deviceReady.subscribe(
() => {
document.addEventListener('backbutton', function (e) {
e.preventDefault();
e.stopPropagation();
this._cordovaService.back();
}.bind(this), false);
}
)
);
I'm sure that function in backbutton is executed (I've logged some information) but the problem still occurs.
More information:
I'm using cordova version 8.0.0
I'm using the following plugins:
https://github.com/TheMattRay/cordova-plugin-wkwebviewxhrfix.git" />
Some hints:
Once, I've built Cordova's android applications which work great (with native JS back function) but after next build, all come back. In hockeyapp I see that in good working version lowest available Android version was 4.1. In new apps, it is 4.4.
I've tried to downgrade Cordova/android engine version but without any positive results.
Additionally, I want to work with the newest libraries available.
Thanks for any help in that case.
I've finally found the solution, based on the following blog's post: http://weblogs.thinktecture.com/thomas/2017/02/cordova-vs-zonejs-or-why-is-angulars-document-event-listener-not-in-a-zone.html, I've added below script just before cordova.js import:
<script>
(function () {
'use strict';
window.addEventListener = function () {
EventTarget.prototype.addEventListener.apply(this, arguments);
};
window.removeEventListener = function () {
EventTarget.prototype.removeEventListener.apply(this, arguments);
};
document.addEventListener = function () {
EventTarget.prototype.addEventListener.apply(this, arguments);
};
document.removeEventListener = function () {
EventTarget.prototype.removeEventListener.apply(this, arguments);
};
})();
</script>
<script type="text/javascript" src="cordova.js"></script>
More about why this error occurring you can read in this GitHub issue: https://github.com/angular/angular/issues/22509
I am a backend developer who got a little project to fix it.
So my boss gives me an electron project which runs on touch devices.
I know that I can listen any key events in Javascript if I use the document object, but in electron it does not work, it says the docuemnt cannot be found.
So implemented this when I or other support guy press the F12 button then the dev tools be rendered out in the electron app.
mainWindow = new BrowserWindow({
'web-preferences': {'web-security': false}
});
mainWindow.onkeydown = function (e) {
console.log("Key down");
if (e.which === 123) {
console.log("Key is F12");
mainWindow.webContents.openDevTools();
}
};
But this code is not working to me. I have no idea how I can listen the F12 button is pressed.
Unfortunately I cannot render out button to the UI which can show the devtools. Because of the customers mustn't press it.
Sometimes I need to see the realtime console tab in devtools on the device.
There is a known issue in Electron ( which has lately been marked as wontfix ) that prevents the usual approach to catch key events using the traditional JS approach.
There also is a small library called electron-localshortcut that circumvents this issue by hijacking the Electron global shortcuts API when the window is active.
Use like this in your main.js:
const electronLocalshortcut = require('electron-localshortcut');
electronLocalshortcut.register(mainWindow, 'F12', () => {
// Open DevTools
});
Without additional libraries you can use "globalShortcut" of electron
const { app, BrowserWindow, globalShortcut } = require("electron");
globalShortcut.register("CmdOrCtrl+F12", () => {
mainWindow.isFocused() && mainWindow.webContents.toggleDevTools();
});
I think F12 is preserved so I use ctrl+f12 which is not far off
You can use the library mousetrap to add global short cut, because it can be installed through node and could bypass the problem of electron mentioned in the accepted answer.
A code example in the render process would be:
var Mousetrap = require('mousetrap');
Mousetrap.bind('4', function() { console.log('4'); });