Keeping page content loaded upon closing the window in Electron - javascript

What I'm trying to achieve is "real" app-like behaviour in a sense that when I close the app on MacOS (hit X, so the app is still in dock) and afterwards open the app from dock again, the webpage content should be there immediately. As I'm trying to build a container for a web-app, the behaviour I'm getting is that every time I open the app, the web page is loaded again causing friction in the UX.
I've tried some dirty workarounds, like calling .hide() on main window from the renderer process before unloading the window:
const {remote} = require('electron');
const main = remote.require('./main.js');
window.onbeforeunload = e => {
main.hideWindow();
e.returnValue = false;
};
and in main process
exports.hideWindow = () => {
mainWindow.hide();
};
But that way I cannot quit my app at all.
Another option I considered was to load the whole mainWindow DOM in the memory, then upon opening the app, in the <webview> preload script load the cached content into the webview and once the page loads, overwrite the webview content, but it also seems very hackish.
I know Slack behaves exactly how I want my app to behave, but I'm struggling to find how they achieve that instant-load (or perhaps not ever closing, except when Quit is selected from the Dock or Cmd+Q is hit).

If I understand your issue correctly then I think there are a couple of standard workarounds for this. Specifically around
...not ever closing, except when Quit is selected from the Dock or
Cmd+Q is hit)
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
And...
open the app from dock again, the webpage content should be there
immediately.
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})

I ended up having a flag which governs the "closing" behaviour
let allowQuitting = false;
and handling the closing like this
function quitApp() {
if (app) {
allowQuitting = true;
app.quit();
}
}
function closeApp() {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.hide();
}
}
On closing, I listen on closing events
function createWindow() {
mainWindow.on('closed', function () {
closeApp();
});
mainWindow.on('close', event => {
if (allowQuitting === false) {
event.preventDefault();
closeApp();
}
});
...
}
app.on('ready', createWindow);
On activating, I first check if the window exists
app.on('activate', function () {
if (mainWindow === null) {
createWindow();
} else {
mainWindow.show();
}
});
The app can be closed using Cmd+Q due to the accelerator:
const template = [{
label: 'Application',
submenu: [
...
{
label: 'Quit', accelerator: 'Command+Q', click: () => quitApp()
}
]
},
...
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
This gives me the desired result, albeit with a side-effect. The app can be closed with Cmd+Q, but can't be closed from the dock (by selecting Quit) or when shutting the system down (says it interrupted the shutdown).

Related

cant click the button (electron)

im try to do a project that connect pc to pc like screencast. when following the coding online im having a problem when trying to click the button. i cant click the button to pup up the id code.
This the code for app.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const { v4: uuid4} = require('uuid');
const screenshot= require('screenshot-desktop');
var socket = require('socket.io-client')('http://172.20.10.3:5000');
var interval;
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 500,
height: 150,
webPreferences: {
preload: path.join(__dirname, 'index.js')
}
})
// and load the index.html of the app.
mainWindow.removeMenu();
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0)
createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin')
app.quit()
})
ipcMain.on("start-share", function(event , arg){
var uuid = uuid4();
socket.emit("join-message", uuid);
event.reply("uuid", uuid);
})
ipcMain.on("stop-share", function(event, arg){
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
This is the index.js file
const ipcRenderer = require ('electron').ipcRenderer;
window.onload = function(){
ipcRenderer.on("uuid", (event, data)=>{
document.getElementById("code").innerHTML = data;
})
}
function startShare(){
ipcRenderer.send("start-share", {} );
document.getElementById("start").style.display = "none";
document.getElementById("stop").style.display = "block";
}
function stopShare(){
ipcRenderer.send("stop-share", {});
document.getElementById("stop").style.display = "none";
document.getElementById("start").style.display = "block";
}
this is the popup when running the code. i cant click the start button
enter image description here
im following this video from (youtube)
this the documentation that i follow in electronelectron website
if someone having problem to see the codes i will try to edit and insert more code or maybe send a zip file. im really needed some help in developed this project for education purpose
im expecting some guide to develop this project. if can i would like the same in the video but i have follow that video from start to end but stuck in the middle of the video. really needed the help
It seems you didn't add your startShare and stopShare functions to your index.html. The preload script is used only for a bridge between your main process and ui process. It doesn't have window object and doesn't attach itself to the index.html.
webPreferences: {
preload: path.join(__dirname, 'index.js')
}
You have to create a bridge and pass ipcRenderer.on function to your ui process. Or you also can add nodeIntegration: true to your webPreferences object. You can read some disadvantages about it.
Then you need to attach your index.js file to the index.html using <script> tag.

How to force the closing of an Electron app?

I have an electron app that loads the URL of the web version of the app.
However I cannot close the application by clicking in the X button and I dont have access to the webapp.
I have tried this:
let count = BrowserWindow.getAllWindows().length;
///returns 1, so there is only 1 window)
window.onbeforeunload=function(e){
e.returnValue=undefined;
return undefined;
}
window.close();
app.quit();
Nothing happens.
app.exit(0) works, but I dont want to use it. Is there a way I can close the app with window.close and app.quit?
EDIT:
The problem are those global beforeunload events. If i click remove in the devtools I am able to close the app.
Also this let names= window.eventNames();returns an array that does not have any beforeunload events
In the file where you created the BrowserWindow, you can attach an event to the 'close' handler for the window. For Electron, this is usually main.js.
const {app, BrowserWindow} = require('electron');
let mainWindow = null;
app.on('ready', () => {
mainWindow = new BrowserWindow({
//options here
});
mainWindow.loadURL([url here]);
//attach event handler here
mainWindow.on("close", () => {
mainWindow = null;
app.quit();
});
});
For good measure, in the case that you may have more than one window, place this in your main.js file.
app.on('window-all-closed', () => {
if(process.platform !== "darwin")
app.quit();
});
You need to save the BrowserWindow object reference. Then listen for a 'closed' event and dereference it:
const { app, BrowserWindow } = require('electron');
let win; // = new BrowserWindow();
win.on('closed', () => {
win = null
})
After dereference, it's all simple, just listen for 'window-all-closed' event on app:
app.on('window-all-closed', () => {
app.quit()
})

How to get the event Handler for stop sharing button in chrome browser in emberjs

I am using twilio API to implement screen sharing in an emberjs app, I am successfully able to share the screen and also toggle on stopping it. Here is my code ->
this.get('detectRtc').isChromeExtensionAvailable(available => {
if (available) {
const { twilioParticipant } = this.get('participant')
if (this.get('stream') && this.get('stream').active) {
this.get('streamTrack').stop()
this.get('userMedia.mediaStream')
.removeTrack(this.get('streamTrack'))
this.set('isEnabled', false)
twilioParticipant.removeTrack(this.get('streamTrack'))
} else {
this.get('detectRtc').getSourceId(sourceId => {
// "cancel" button is clicked
if (sourceId !== 'PermissionDeniedError') {
// "share" button is clicked extension returns sourceId
this.get('userMedia')
.getScreen(sourceId)
.then(mediaStream => {
this.set('isEnabled', true)
this.set('stream', mediaStream)
this.set('streamTrack', mediaStream.getVideoTracks()[0])
twilioParticipant.addTrack(mediaStream.getVideoTracks()[0])
})
.catch(() => { /* do nothing, but return something */ })
}
})
}
} else {
this.get('flash').status(
'base',
this.get('intl').t('chromeExtension.install'),
{
icon: 'alert-circle',
push: true
}
)
// TODO Show the system popup to install chrome extension from web store
// !!chrome.webstore &&
// !!chrome.webstore.install &&
// chrome.webstore.install(this.webStoreUrl)
}
})
The issue I'm facing is with the stop sharing button which is at the bottom of the app as seen in screenshot below
I need a way to listen to an event handler and execute the some code after clicking on the stop sharing screen button, I know there is an onended event Handler which is mentioned in the MediaStreamTrack docs, but I don't know how to use it, any help will be highly appreciated.
https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack
The "stop sharing" button will trigger the MediaStreamTracks 'ended' event. Try this:
mediaStream.getVideoTracks()[0].addEventListener('ended', () => console.log('screensharing has ended'))
for some reason, #philipp answer is not working for me and I found this quite helpful
https://github.com/webrtc/samples/blob/gh-pages/src/content/getusermedia/getdisplaymedia/js/main.js#L88
this.get('stream').addEventListener('inactive', e => {
console.log('Capture stream inactive - stop recording!');
});

Electron prevent main window from closing

I am writing an application in electron where if a user has a unsaved file open I want to prompt the user before saving it. I found this example code online:
window.onbeforeunload = (e) => {
var answer = confirm('Do you really want to close the application?');
e.returnValue = answer; // this will *prevent* the closing no matter what value is passed
if(answer) { mainWindow.destroy(); } // this will close the app
};
This code strangely works if the dialogs Yes, Cancel or X button is pressed within a few seconds of appearing but if you let the dialog rest on screen for a little and then click a button the application will close no matter what is pressed.
This code is located in the my main script file called by index.html
Really strange behavior! I cannot explain why it's happening, but can give you a workaround implemented in main process.
You can use electron's dialog module and create the same confirmation dialog with electron. This one works as expected.
main.js
const { app, BrowserWindow, dialog } = require('electron')
const path = require('path')
app.once('ready', () => {
let win = new BrowserWindow()
win.loadURL(path.resolve(__dirname, 'index.html'))
win.on('close', e => {
let choice = dialog.showMessageBox(
win,
{
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Do you really want to close the application?'
}
)
if (choice === 1) e.preventDefault()
})
})
It might be possible only when DevTools window is activated.
In any case, prefer working with the event close as pergy suggested above. This is so far the best approach.
But be aware that e.preventDefault() is spreading everywhere in the code. Once you managed properly the preventDefault() you need to turn the variable e.defaultPrevented = false to get back to the natural behavior of your app.
Actually, it seems e.preventDefault() function is turnind the variable e.defaultPrevented to true until you change its value.
In my case, I had to use a variable called modificationEnCours which is true when I don't want to close my window and then false if I want to like that:
let mainWindow
let mainMenu // Menu de la fenĂȘtre principale
app.on('ready', () => {
// Listen for app to be ready
// Create the mainWindow
mainWindow = new BrowserWindow({
width: 1024,
height: 768,
minHeight: 350,
minWidth: 500,
frame: true,
webPreferences: {
nodeIntegration: true
}
})
// Quit app when window is closed
mainWindow.on('close', function(e){
console.log('close')
if (modificationEnCours){
e.preventDefault()
if(msgBoxVerifieSauvegarde('Question','Voulez-vous enregistrer avant de quitter ?')) {
modificationEnCours=false
app.quit()
}
} else if (process.platform !== 'darwin') {
modificationEnCours=false
app.quit()
mainWindow = null
}
})
// Load html in window
mainWindow.loadFile(path.join(__dirname, 'mainWindow.html'))
// Build menu from template
mainMenu = Menu.buildFromTemplate(mainMenuTemplate)
// Insert menu
Menu.setApplicationMenu(mainMenu)
})

How to catch the event of clicking the app window's close button in Electron app

I wish to catch the event of clicking the app window's close button in Electron app.
I'm trying to develope Electron app for Mac OSX.
I want to hide the app window, not to terminate the app when a user clicks the window's close button like other Mac apps.
However, I can not detect wether the system should be terminated or it should be hidden, because in any case, a close event of browser-window is called when a close button is clicked, the OS is shut down or the app is terminated with quit command, Cmd+Q.
Is there any way to catch the event of clicking the app window's close button in Electron app?
Thank you for your help.
Postscript
To detect the event of clicking a close button, I tried this code
var app = require('app');
var BrowserWindow = require('browser-window');
var Menu = require('menu');
var force_quit = false;
var menu = Menu.buildFromTemplate([
{
label: 'Sample',
submenu: [
{label: 'About App', selector: 'orderFrontStandardAboutPanel:'},
{label: 'Quit', accelerator: 'CmdOrCtrl+Q', click: function() {force_quit=true; app.quit();}}
]
}]);
app.on('window-all-closed', function(){
if(process.platform != 'darwin')
app.quit();
});
app.on('ready', function(){
Menu.setApplicationMenu(menu);
mainWindow = new BrowserWindow({width:800, height:600});
mainWindow.on('close', function(e){
if(!force_quit){
e.preventDefault();
mainWindow.hide();
}
});
mainWindow.on('closed', function(){
console.log("closed");
mainWindow = null;
app.quit();
});
app.on('activate-with-no-open-windows', function(){
mainWindow.show();
});
});
With this code, the app is hidden when a close button of the app window is clicked, and the app is terminated when Cmd+Q is typed. However, when I try to shut down the OS, the shutdown event is prevented.
You can catch it by using the close event of the browser-window api. You can try the following to verify this...
var app = require('app');
var force_quit = false;
app.on('ready', function () {
mainWindow = new BrowserWindow({ width: 800, height: 600 });
mainWindow.on('close', function() { // <---- Catch close event
// The dialog box below will open, instead of your app closing.
require('dialog').showMessageBox({
message: "Close button has been pressed!",
buttons: ["OK"]
});
});
});
Update:
To separate functionality you can do the following...
var app = require('app');
var BrowserWindow = require('browser-window');
var Menu = require('menu');
var force_quit = false;
var menu = Menu.buildFromTemplate([
{
label: 'Sample',
submenu: [
{label: 'About App', selector: 'orderFrontStandardAboutPanel:'},
{
label: 'Quit',
accelerator: 'CmdOrCtrl+Q',
click: function() {
force_quit=true; app.quit();
}
}
]
}]);
app.on('window-all-closed', function(){
if(process.platform != 'darwin')
app.quit();
});
app.on('ready', function(){
Menu.setApplicationMenu(menu);
mainWindow = new BrowserWindow({width:800, height:600});
// Continue to handle mainWindow "close" event here
mainWindow.on('close', function(e){
if(!force_quit){
e.preventDefault();
mainWindow.hide();
}
});
// You can use 'before-quit' instead of (or with) the close event
app.on('before-quit', function (e) {
// Handle menu-item or keyboard shortcut quit here
if(!force_quit){
e.preventDefault();
mainWindow.hide();
}
});
// Remove mainWindow.on('closed'), as it is redundant
app.on('activate-with-no-open-windows', function(){
mainWindow.show();
});
});
// This is another place to handle events after all windows are closed
app.on('will-quit', function () {
// This is a good place to add tests insuring the app is still
// responsive and all windows are closed.
console.log("will-quit");
mainWindow = null;
});
The above code uses the before-quit event handler to handle app "close" events on the app api. Browser-window "close" events are still handled on the browser-window api by mainWindow.on('close').
Additionally, the will-quit event is a better place to test for problems before the app closes completely.
app.on('ready', ()=> {
let win = new BrowserWindow({width:800, height:600})
win.loadURL('file://'+__dirname+'/index.html')
win.on('closed', () => {
console.log(' ---- Bye Bye Electron ---- ')
});
})
Thus You Can catch the Close Event

Categories