Electron.js prevent windows close conditionally - javascript

I want to ask user if he really want to close an electron app.
Accordingly to docs - I've tried:
window.onbeforeunload = (e) => {
const answer = confirm('Do you want to close the application?');
e.returnValue = answer;
if (answer) { window.close(); }
};
But my app still closes no matter what user choose.
How to prevent close an Electron app conditionally?

I guess, I have an answer.
It shouldn't be called in renderer process.
Instead we should use mainWindow in main process for such operation and 'close' lifecycle method, which will be called right before closing.
this.mainWindow.on('close', (e) => {
const choice = this.dialog.showMessageBox(
this.mainWindow,
{
type: 'question',
buttons: ['Yes', 'No, hang on', 'third option'],
title: 'Confirm your actions',
message: 'Do you really want to close the application?'
}
);
console.log('CHOICE: ', choice);
if (choice > 0) e.preventDefault();
});
choice const will return an answer from buttons array, so 'Yes' will be as confirm and for other options we can prevent actions.
NOTE: I've pasted with this. from my code, but, obviously mainWindow is your BrowserWindow instance and this.dialog is electron.dialog that imported from import electron from 'electron';

To conditionally close window in Electron ^15, do:
win.on('close', async e => {
e.preventDefault()
const { response } = await dialog.showMessageBox(win, {
type: 'question',
title: ' Confirm ',
message: 'Are you sure that you want to close this window?',
buttons: ['Yes', 'No'],
})
response === 0 && win.destroy()
})

Related

Send IPC message from main process to renderer process Electron

Currently I have an Electron menu with a save button on it. When this save button is pressed I wish to send an event to the renderer process, for the renderer to handle the event.
Here is what I have attempted:
Menu Source
const menuTemplate = [
{
label: "File",
submenu: [
{
label: "Save",
accelerator: "Ctrl+S",
click: () => {
BrowserWindow.getFocusedWindow().webContents.send("save");
}
},
]
},
]
Renderer Source
ipc.on("save", () => {
console.log("save");
})
Preload source
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("ipc", { on: ipcRenderer.on });
When trying this I get no output whatsoever when pressing the save button, including no errors. I can confirm that the correct menu is being utilised by Electron and that the click() function is executing. I can also confirm that ipc.on is indeed defined in the renderer.
How can I get this working? Thanks in advance.
Try setting the this manually in the on function.
contextBridge.exposeInMainWorld("ipc", { on: ipcRenderer.on.bind(ipcRenderer) });
or make a new function that passes the args:
contextBridge.exposeInMainWorld("ipc", { on(event, fn) { ipcRenderer.on(event, fn) } });

Trying to get to the popup window (sign up) form after clicking on 'sign up' button using cypress

I am navigating to this website https://www.twitch.tv/ and to register a new user.
I am performing those steps:
navigating to the page.
clicking on sign up button
moving to popup and clicking on log in
then a sign up pop up window comes up.
I am trying to get this window but my application does not recognize the page and I am getting an error. please mind the image attached:
this is my code:
describe('RegisterTwitchTv', function() {
it('Register New User', function() {
cy.visit('')
cy.title().should('eq', 'Twitch')
cy.get('button[data-a-target="signup-button"]').click()
// cy.on('window:confirm', ($alertElement) => {
// expect($alertElement).to.equal('Log in')
// }).click
cy.contains('Log in').click()
cy.window().then((win) => {
cy.get('button[class~="tw-pd-x-1"]').click()
})
})
})
but my code does not recognize the new window which is the one I want to handle.
Unfortunately accessing new windows via Cypress is not possible in its current version.
I would be a good practice to test this functionality using two isolated tests:
describe('RegisterTwitchTv', () => {
// Check the popup is opened
it('Register New User popup is opened', () => {
cy.visit('', {
onBeforeLoad(win) {
cy.stub(win, 'open');
}
});
cy.title().should('eq', 'Twitch')
cy.get('button[data-a-target="signup-button"]').click();
cy.contains('Log in').click();
cy.window()
.its('open')
.should('be.called');
});
// Check the login works
it('Register New User2 login', () => {
cy.visit('/login?popup=true');
cy.get('button[class~="tw-pd-x-1"]').click()
cy.get('#signup-username').type('test#test.com');
...
...
});
});

PMA Service worker notification click isn't working

I am trying to show a notification and do something when it is clicked. The part that shows is working well, is receiving data from the server, however, the function of clicking on the notification does not work, I have done everything the documentation says, what I found on the web and here, everything points with the same functionality that I have implemented but it doesn't seem to work. I have made fictitious practices and as long as the data is not loaded from the server, the click is triggered, otherwise, with the data it does not.
Can anyone tell me what I am doing wrong? I'll really apreciate some help, I've two days with this.
self.addEventListener('push', (e) => {
let notification = e.data.json();
const title = 'My app ' + notification.title;
const options = {
body: notification.msg,
actions: [
{ action: 'yes', title: 'Aprobar' },
{ action: 'no', title: 'Rechazar' }
]
};
self.registration.showNotification(title, options);
}); //to show the notification with server info
self.addEventListener('notificationclick', function (event) {
console.log(event);
var noti = event.notification.data;
let r = event.notification.data.json();
console.log(noti); },
false); //handling the click
I've also tried with notificationclose to see if it catchs the click but it does not work either.
Important to note that it does not display any error or warning, it does simple do anything. Found the solution! See First Answer.
I found the solution! After playing around with the code and reading some others documents, it turns out that if my service on my server is a threading type, in my js has to be waiting for an answer. If someone needs it.
let notification = '';
self.addEventListener('push', (e) => {
notification = e.data.json();
const title = 'My app' + notification.title;
const options = {
body: notification.msg,
actions: [
{ action: 'yes', title: 'Aprobar' },
{ action: 'no', title: 'Rechazar' }
]
};
e.waitUntil(self.registration.showNotification(title, options)); }); //waitUntil to show the notification
self.addEventListener('notificationclick', function (event) {
console.log('[Service Worker] Notification click Received.');
event.notification.close();
let response = event.action;
event.waitUntil(
fetch(`api/authorizations/processor?uuid=${notification.uuid}&response=${response}&account=${notification.user}`,
{
method: 'GET',
mode: 'cors',
cache: 'default'
}).then((result) => {
if (!result.ok)
throw result;
return result.json();
}).then(function (data) {
console.log(data);
}).catch(function (error) {
console.log(errow);
})
); }); // waitUntil to expect a action

Are there events for when an Electron app is shown and hidden?

I have been looking for Electron app events for when the application is shown or hidden. I see in the docs that there is 'browser-window-blur' and 'browser-window-focus' but those do not do what I want.
I would like to know when the user has switched to another application or switched back to my app. The above events get triggered if the user switches between browser windows – including the "developer's tools" window.
The code in main.js
app.on('browser-window-focus', () => {
if (mainWindow) {
console.log('browser-window-focus');
mainWindow.webContents.send('projectMsg', { "event": "focus" });
}
});
app.on('browser-window-blur', () => {
console.log('browser-window-blur');
if (mainWindow) {
mainWindow.webContents.send('projectMsg', { "event": "blur" });
}
});
It seems to me that it works exactly as you described, so maybe the requirements are different.
This code
const {app, BrowserWindow} = require('electron')
app.on('browser-window-focus', (event, win) => {
console.log('browser-window-focus', win.webContents.id)
})
app.on('browser-window-blur', (event, win) => {
if (win.webContents.isDevToolsFocused()) {
console.log('Ignore this case')
} else {
console.log('browser-window-blur', win.webContents.id)
}
})
app.once('ready', () => {
new BrowserWindow()
new BrowserWindow().webContents.openDevTools({detach: true})
})
works the following way (in 3.0.3) given that nothing is focused initially:
Clicking on window 1 prints browser-window-focus 1
Clicking on window 2 prints browser-window-blur 1 browser-window-focus 2
Clicking on devtools window prints browser-window-blur 2 Ignore this case
So as far as I see devtool is not included in these events, windows are getting blurred for any other window focused (including devtool)
There is also show and hide, though you have to explicitly show/hide the app with win.show() and win.hide() to trigger these events.
Check out of these BrowserWindow's events:
Event: 'blur': Emitted when the window loses focus.
Event: 'show': Emitted when the window is shown.
For example:
app.once('ready', () => {
let mainWindow = new BrowserWindow({show: false}) //Create main window
mainWindow.on('show', () => {
//Do something
})
})
Hope this help.

inline keyboard click doesnt call callback_query why?

bot.onText(/(.+)$/, function (msg, match) {
const opts = {
reply_markup: {
inline_keyboard: [
[
{
text: 'Edit Text',
callback_data: 'edit'
}
]
]
}
};
bot.sendMessage(msg.from.id, 'Original Text', opts);
});
bot.on("callback_query", function(callbackQuery) {
// 'callbackQuery' is of type CallbackQuery
console.log(callbackQuery);
});
I have looking for answer to this question, tried all the resources available on call_back. Such as
Telegram bot inline keyboard via Node.JS
Telegram inline keyboard and keyboard
How can create menu for telegram bot in bot father?
How about trying this like that?
bot.on('callback_query', function onCallbackQuery(callbackQuery) {
const action = callbackQuery.data;
const msg = callbackQuery.message;
// do your stuff
if (action === 'adress') {
// do something if callback data is "adress", you can have multiple if statements for various cases
}
});
That's how I got it working, hope it helps!

Categories

Resources