Im fairly new in the programming world. I'm making an app where it should be possible to choose a directory, where to save some generated files.
I'm working with the ipc, and it seems like some of the code works, but it looks like i can't get the mainIpc to send the path back to the renderer.
I hope the hive can help, thanks in advance!
Renderer:
const electron = require("electron");
const ipc = require("electron").ipcRenderer;
createBtn.addEventListener("click", (event) => {
ipc.send("path:get");
});
ipc.on("path:selected", function (path) {
console.log("Full path: ", path);
});
Main
const ipc = require("electron").ipcMain;
const os = require("os");
const { dialog } = require("electron");
ipc.on("path:get", function (event) {
if (os.platform() === "linux" || os.platform() === "win32") {
dialog.showOpenDialog(
{
properties: ["openFile"],
},
function (files) {
if (files) win.webContents.send("path:selected", files[0]);
console.log("SENT");
}
);
} else {
dialog.showOpenDialog(
{
properties: ["openFile", "openDirectory"],
},
function (files) {
if (files) win.webContents.send("path:selected", files[0]);
console.log("SENT");
}
);
}
});
Edit: Adding the setup
Setup
const { app, BrowserWindow } = require("electron");
const ipc = require("electron").ipcMain;
const os = require("os");
const { dialog } = require("electron");
try {
require("electron-reloader")(module);
} catch (_) {}
let win;
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
},
});
win.loadFile("./src/index.html");
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
I figured it out with some kind help.
So if anyone needs the same procedure i'll try to explain what i got to.
So, in the main, i had to add a then, because the showDialog returns a promise
if (os.platform() === "linux" || os.platform() === "win32") {
dialog
.showOpenDialog({
properties: ["openFile", "openDirectory"],
})
.then((result) => {
if (result) win.webContents.send("path:selected", result.filePaths);
})
.catch((err) => {
console.log(err);
});
} else {
dialog
.showOpenDialog({
properties: ["openFile", "openDirectory"],
})
.then((result) => {
console.log(result.filePaths);
if (result) win.webContents.send("path:selected", result.filePaths);
})
.catch((err) => {
console.log(err);
});
}
});
This sends back an array with the path at [0]
in the renderer i forgot to add the event as an parameter.
ipc.on("path:selected", (event, path) => {
chosenPath = path;
console.log("Full path: ", chosenPath[0]);
});
Related
I have the following code (main.js) :
const console = require('console');
const {
app,
BrowserWindow,
BrowserView,
screen,
globalShortcut,
ipcMain
} = require('electron');
const path = require('path');
if (require('electron-squirrel-startup')) {
app.quit();
}
const createWindow = () => {
const view = new BrowserView();
mainWindow = new BrowserWindow({
width: 400,
height: 600,
frame: false,
resizable: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
webviewTag: true,
nodeIntegration: true,
contextIsolation: false,
},
});
mainWindow.webContents.openDevTools();
mainWindow.loadFile(path.join(__dirname, 'home.html'));
globalShortcut.register('q', () => {
app.quit()
});
globalShortcut.register('h', () => {
mainWindow.setSize(400, 600);
var xx = Math.round(screen.getPrimaryDisplay().workAreaSize.width / 2 - 200);
var yy = Math.round(screen.getPrimaryDisplay().workAreaSize.height / 2 - 300);
mainWindow.setPosition(xx, yy, true);
mainWindow.resizable = false;
mainWindow.loadFile(path.join(__dirname, 'home.html'));
});
globalShortcut.register('1', () => {
mainWindow.resizable = true;
mainWindow.setPosition(0, mainWindow.getPosition()[1]);
mainWindow.setSize(screen.getPrimaryDisplay().workAreaSize.width, 64);
mainWindow.loadURL('https://example.com?variable=static');
});
globalShortcut.register('2', () => {
var size = mainWindow.getSize();
mainWindow.resizable = true;
mainWindow.setPosition(0, mainWindow.getPosition()[1]);
mainWindow.setSize(size[0], 128);
mainWindow.loadURL('https://example.com?variable=static');
});
globalShortcut.register('3', () => {
var size = mainWindow.getSize();
mainWindow.resizable = true;
mainWindow.setPosition(0, mainWindow.getPosition()[1]);
mainWindow.setSize(size[0], 128 + 55);
mainWindow.loadURL('https://example.com?variable=static');
});
};
app.on('ready', function () {
createWindow();
ipcMain.on('form-submitted', (event, variable) => {
console.log('Form submitted with conference name:', variable);
event.sender.loadURL('https://example.com?variable=' + variable);
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
app.on('will-quit', () => {
globalShortcut.unregisterAll()
})
When I press 1, 2 or 3 the window refreshes the correct URL.
But the moment I set the variable in the URL it stops working; it says it's unable to run jQuery (yes, remote website has javascript).
I wonder if this is a 'security' feature ?
I have tried turning webSecurity parameter to off, no luck.
What am I missing here ?
I am trying achieve something where I can directly send data to react and where in react whenever it receives it does something.
So my electron.js is in below format.
// ./public/electron.js
const path = require("path");
const { app, BrowserWindow, ipcMain} = require("electron");
const isDev = false; //require("electron-is-dev"); //false
let splash = null;
let win = null;
let etmf_obj = null;
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 1920,
height: 1080,
webPreferences: {
nodeIntegration: true,
contextIsolation: true,
enableRemoteModule: true,
preload: path.join(__dirname, "./preloadDist.js"),
},
});
// win.loadFile("index.html");
win.loadURL(
isDev
? "http://localhost:3000"
: `file://${path.join(__dirname, "../build/index.html")}`
);
// Open the DevTools.
if (!isDev) {
win.webContents.openDevTools({ mode: "undocked" });
}
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
function restartApp() {
console.log("restarting app..");
app.exit();
app.relaunch();
}
//IPC SECTION
ipcMain.handle("notify", (event, args) => {
console.log("from react I got" + args);
console.log("hello from electron via react"); //this one works as expected
});
ipcMain.on("splashDone", function () {
console.log("splash done");
});
ipcMain.on("relaunchApp", function () {
restartApp();
});
ipcMain.on("closeAll", function () {
app.quit();
});
ipcMain.on("callAnim", function (args) {
win.webContents.send("showAnimation", args);// trying to send data directly to
//react here but don't know whether its right way or not
});
and my preload file preloadDist.js is in below format
const { ipcRenderer, contextBridge } = require("electron");
contextBridge.exposeInMainWorld("electron", {
notificationApi: {
sendNotification(message) {
ipcRenderer.invoke("notify", message);
},
},
batteryApi: {},
filesApi: {},
splashStatus: {
splashDone() {
ipcRenderer.invoke("splashDone")
}
},
});
and react to call function of or to send data I am do this
for example to send notification data :
<button
className="speak_border"
onMouseEnter={() => setHovermic(true)}
onMouseLeave={() => setHovermic(false)}
onClick={() => {
soundwave();
window.electron.notificationApi.sendNotification(
"From react Hi!");
}}
>
and to receive data I am not able to figure out but as I am doing win.webContents.send("showListenAnimation", args);
I am not able to understand how this will be received at the react end
what I tried is:
useEffect(() => {
try {
window.electron.on(
"showAnimation",
function (event, data) {
if (data) {
setAnim(true);
}
if (!data) {
setAnim(false);
}
}
);
} catch (e) {
console.log("issue with on getting data");
}
});
But this way I am getting error and not able to figure out the way to receive, but sending data from react to electron is working perfectly fine!
Please guide on this and how to achieve with about preload.js and electron.js
format.
I'm pretty new to Electron... whenever a new window is opened, I want a new window to be created by Electron. This works fine and occurs at "app.on('new-window',...". Although the newBrowser window is created, none of the option seem to be considered. The new browser window isn't 64 tall and the other options also don't work. Anyone have any suggestions?
/* main.js v1 */
const { app, BrowserWindow } = require('electron')
const { webContents } = require('electron')
const path = require('path')
const url = require('url')
let win
function createWindow () {
win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL(url.format({
pathname: 'localhost:3500/session',
protocol: 'http:',
slashes: true
}))
win.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const allWindows = BrowserWindow.getAllWindows()
for (let i = 0; i < allWindows.length; i++) {
const win = allWindows[i]
if (win.webContents.getURL() === navigationUrl) {
win.close()
return
}
}
})
})
win.on('closed', () => {
win = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (win === null) {
createWindow()
}
})
app.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const allWindows = BrowserWindow.getAllWindows()
for (let i = 0; i < allWindows.length; i++) {
const win = allWindows[i]
if (win.webContents.getURL() === navigationUrl) {
win.close()
return
}
}
})
})
app.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
if (frameName === 'modal') {
// open window as modal
event.preventDefault()
Object.assign(options, {
modal: true,
parent: win,
height: 250,
})
event.newGuest = new BrowserWindow(options)
}
})
I've been working on updating a electron app from 11.x to 12.x and have run into an issue where the apis declared by contextBridge.exposeInMainWorld come as undefined when called upon through window.
This is my preload.js file
const { contextBridge, ipcRenderer } = require('electron');
const { path } = require('path')
contextBridge.exposeInMainWorld('api',{
getPath: (filePath) => {
return path.parse(filePath).base;
},
removeAllListeners: (ListenerType) => {
ipcRenderer.removeAllListeners(ListenerType);
},
openNewPDF: (pdf) => {
ipcRenderer.send('openNewPDF',pdf);
},
newWindow: (file) => {
ipcRenderer.send('newWindow',file);
},
togglePrinting: (value) => {
ipcRenderer.send('togglePrinting',value)
},
resizeWindow: (value) => {
ipcRenderer.send('resizeWindow', value)
}
});
my app.js
function createWindow(filename = null) {
// Create the browser window.
let win = new BrowserWindow({
width: 550,
height: 420,
minWidth: 565,
minHeight: 200,
preload: path.resolve(path.join(__dirname, 'app/preload.js')),
resizable: true,
titleBarStyle: 'default',
show: false
});
wins.push(win);
// and load the index.html of the app.
win.loadFile('app/index.html');
win.openDevTools();
let wc = win.webContents
wc.on('will-navigate', function (e, url) {
if (url != wc.getURL()) {
e.preventDefault()
shell.openExternal(url)
}
})
win.once('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.
wins = [];
});
win.webContents.removeAllListeners('did-finish-load');
win.webContents.once('did-finish-load', () => {
if (filename) {
win.webContents.send('file-open', filename);
win.show();
} else {
win.show();
}
});
if (!menuIsConfigured) {
const menu = Menu.buildFromTemplate(menuTemplate);
menu.getMenuItemById('file-open').click = () => {
openNewPDF();
};
menu.getMenuItemById('file-print').click = () => {
const focusedWin = BrowserWindow.getFocusedWindow();
focusedWin.webContents.send('file-print');
};
Menu.setApplicationMenu(menu);
menuIsConfigured = true;
}
const openNewPDF = () => {
dialog
.showOpenDialog(null, {
properties: ['openFile'],
filters: [{ name: 'PDF Files', extensions: ['pdf'] }]
})
.then((dialogReturn) => {
const filename = dialogReturn['filePaths'][0];
if (filename) {
if (wins.length === 0) {
createWindow(filename.toString());
} else {
const focusedWin = BrowserWindow.getFocusedWindow();
if (focusedWin) {
focusedWin.webContents.send('file-open', filename.toString());
}
}
}
});
}
ipcMain.removeAllListeners('togglePrinting');
ipcMain.once('togglePrinting', (e, msg) => {
const menu = Menu.getApplicationMenu();
menu.getMenuItemById('file-print').enabled = Boolean(msg);
});
ipcMain.removeAllListeners('newWindow');
ipcMain.once('newWindow', (e, msg) => {
console.log('opening ', msg, ' in new window');
createWindow(msg);
});
ipcMain.removeAllListeners('resizeWindow');
ipcMain.once('resizeWindow', (e, msg) => {
const { width, height } = win.getBounds();
if (width < 1000 || height < 650) {
win.setResizable(true);
win.setSize(1000, 650);
win.center();
}
});
ipcMain.removeAllListeners('openNewPDF');
ipcMain.once('openNewPDF', (e, msg) => {
openNewPDF();
});
}
let fileToOpen = '';
const args = process.argv;
const argsLength = args.length;
if (argsLength > 1 && args[argsLength - 1].endsWith('.pdf')) {
fileToOpen = args[argsLength - 1];
}
app.on('open-file', (event, path) => {
event.preventDefault();
if (app.isReady()) {
if (wins.length === 0) {
createWindow(path.toString());
} else {
const focusedWin = BrowserWindow.getFocusedWindow();
focusedWin.webContents.send('file-open', path.toString());
}
}
fileToOpen = path.toString();
});
app.whenReady().then(() => {
if (fileToOpen) {
createWindow(fileToOpen);
} else {
createWindow();
}
});
app.on('window-all-closed', () => {
app.quit()
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
I'm lost on why contextBridge doesn't work.
The object passed to the BrowserWindow constructor is not correct. The preload option should be a property of webPreferences
const win = new BrowserWindow({
webPreferences: {
preload: YOUR_PRELOAD_SCRIPT_PATH
}
});
See the docs
I am trying to download an .zip file from discord and extracting using decompress package, but it not return any errors and don't extract the package. (The file is saving and downloading correctly)
const decompress = require('decompress');
client.on("message", (msg) => {
if (msg.author.id === process.env.REIS_ID) {
if (msg.channel.id === config.channel_commit) {
if (config.file_status === 0) {
if (msg.attachments.first()) {
download_files(msg.attachments.first().url).then(res => {
console.log(res);
});
}
} else {
msg.reply("Upload ainda em processo.");
}
}
}
});
const download_files = async (url) => {
const stream = got.stream(url);
const file_ext = FileType.fromStream(stream).then(async (res) => {
got
.stream(url)
.pipe(
fs.createWriteStream("./testes/a/new." + res.ext, { overwrite: true})
);
console.log(res.ext);
if (res.ext === "zip") {
console.log("zip file");
const files = await decompress("./testes/a/new.zip", "./testes/a/new/");
}
});
};
Solution:
I download the unzip module from npm and make that the zip file is not saved to the folder, the request saves directly the extracted files.
Code:
client.on("message", (msg) => {
if (msg.author.id === process.env.REIS_ID) {
if (msg.channel.id === config.channel_commit) {
if (msg.attachments.first()) {
let res = download_files(msg.attachments.first().url);
}
}
}
});
const download_files = (url) => {
const stream = got.stream(url);
const file_ext = FileType.fromStream(stream).then(async (res) => {
got
.stream(url)
console.log(res.ext);
if (res.ext === "zip") {
got.stream(url).pipe(unzip.Extract({ path: "./testes/a/new/" }));
}
});
};