In my renderer I can emit an event to create a PDF. However, before writing to disk I'd like to first open the newly cerated PDF in another window. How can I circumvent the writing to the file system and use data as my source for loadURL?
My code so far:
ipcMain.on('view-pdf', (event, url) => {
let pdf
mainWindow.webContents.printToPDF({}, (error, data) => {
if (error) throw error
pdf = data
// what's the magic here to make pdf work?
})
const pdfWindow = new BrowserWindow({
width: 1024,
height: 800,
webPreferences: {
plugins: true,
webSecurity: false
}
})
pdfWindow.loadURL(pdf)
})
The async nature of Javascript is a beast. This works as expected:
ipcMain.on('view-pdf', (event, url) => {
mainWindow.webContents.printToPDF({}, (error, data) => {
if (error) throw error
const pdf = data.toString('base64')
const pdfWindow = new BrowserWindow({
width: 1024,
height: 800,
webPreferences: {
plugins: true,
webSecurity: false
}
})
pdfWindow.loadURL('data:application/pdf;base64,' + pdf)
})
})
The code is not perfect but this is how it works.
Related
main.js
//...
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, './preload/preload.js')
}
});
//...
preload.js
const { contextBridge, ipcRenderer } = require('electron');
const qrcode = require('qrcode');
contextBridge.exposeInMainWorld('electronAPI', {
qrc: qrcode
})
the error
Unable to load preload script: F:\project\bluetools\preload\preload.js
Error: module not found: qrcode
Although direct exposure is not a good behavior, but I need to do it; and the example in the official documentation can be exposed directly, although it is not recommended; but why I require any third-party package in preloadjs shows "module not found: xxx"
Just add nodeIntegration: true to webPreferences. Like that.
//...
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, './preload/preload.js')
}
});
//...
I refer to here, I have got a solution, but it seems to be more troublesome, but what is this compared to security and normative?
ipc.js
module.exports = {
xxx_req: (argements) => {
const { ipcMain, winb: win } = argements;
ipcMain.on('xxx_req', (event, response) => {
win.webContents.send("xxx", "hello");
});
}
}
main.js
const ipcm = require('./ipc.js');
const createWindow = () => {
const win = new BrowserWindow({...});
ipcm.xxx_req({ ipcMain, winb: win })
}
preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
xxx_req: (response) => ipcRenderer.send('xxx_req',response),
xxx: (callback) => ipcRenderer.on('xxx',callback),
})
index.js(render process)
window.electronAPI.xxx_req("hello");
window.electronAPI.qrcode((event, detail) => {
console.log(detail)
});
If you still don't understand why I did this, please refer to here.
I have no idea what is happening here, basically I tried to print a document in electron using webContents.print, by silent print, but this error occurs and the printer only prints the document a single time, after that the print queue is filled with new orders, but the error still happening and the file is not printed.
Some code of what I am trying to do:
ipcMain.handle('imprimir', async (event, args) => {
console.log(args);
const ticket = new BrowserWindow({
width: 300,
height: 400,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false
}
});
ticket.loadFile('src/views/ticket.html')
.then(() => {
ticket.webContents.send('enviar-pedido', args);
var options = {
silent: true,
deviceName: 'HP Deskjet 2000 J210 series',
printBackground: true,
color: false,
margin: {
marginType: 'printableArea'
},
landscape: false,
pagesPerSheet: 1,
collate: false,
copies: 1,
/*pageSize: { height: 600, width: 353 }*/
}
ticket.webContents.print(options, (success, failureReason) => {
if (!success) {
console.log(failureReason);
}
console.log('Print Initiated');
ticket.close();
});
});
Note: I do not speak fluent English and this is my first question here, I am sorry if I commited some mistake.
I ran into this just the other day.
I determined the error does not appear with the BrowserWindow option
nodeIntegration: false
If you do not need nodeIntegration in the HTML loaded into the ticket window you should be able to turn this off.
I am looking to try to redirect users from "home.html" to "dashboard.html". I've searched far and wide, yet I haven't found an answer.
When creating your window with the BrowserWindow module, you would have used the method win.loadFile(filePath[, options]) to load your html file.
Once the logic to change pages is successful, all you need to do is execute the win.loadFile(filePath[, options]) line of code again with the path to your new file.
As win.loadFile(filePath[, options]) returns a promise, let's add a .then() statement as well (though not requried).
main.js (main thread)
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const nodePath = require("path");
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('home.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
// Run when logic to change to dashboard is successful.
function showDashboard() {
window.loadFile('dashboard.html')
.then(() => { window.show(); })
}
I'm trying to figure out how to exchange messages between the main process and the BrowserView.
I've been using the ipc between the main process and the renderer process within a "simple" react renderer page.
But now, using the same technique, I do not see the received message in the console of the BrowserView, which, as far as I understand, seems to behave differently from a "normal" react renderer page.
And this SOF post seems confirm my hypothesis: Electron BrowserView Renderer process vs WebView
In preload I defined:
declare global {
interface Window {
api: {
electronIpcSend: (channel: string, ...arg: any) => void;
electronIpcOn: (channel: string, listener: (event: any, ...arg: any) => void) => void;
}
}
}
In main I have :
function createWindowTypeC (url_string: string) {
WindowTypeC = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
sandbox: true,
nodeIntegrationInSubFrames: false,
webSecurity: true,
webviewTag: false,
preload: path.join(__dirname, "./preload/preload.js"), /* eng-disable PRELOAD_JS_CHECK */
}
})
// and load the index.html of the app.
// Emitted when the window is closed.
WindowTypeC.on('closed', () => {
WindowTypeC.removeBrowserView(view_C)
WindowTypeC = null
})
enforceInheritance(WindowTypeC.webContents)
// https://www.electronjs.org/docs/latest/api/browser-view
let view_C = new BrowserView()
view_C.webContents.once('did-finish-load', () => {
contents.focus()
view_C.webContents.send('ping', 'whoooooooooh!')
})
view_C.setAutoResize({
width: true,
height: true,
horizontal: true,
vertical: true
})
WindowTypeC.setBrowserView(view_C)
view_C.setBounds({ x: 0, y: 0, width: 800, height: 600 })
view_C.setBackgroundColor("#1e1e1e")
setTimeout(() => {
view_C.webContents.loadURL(url_string)
}, 200)
view_C.webContents.openDevTools({
mode: 'left'
})
}
While in the App_C.tsx I have:
import * as React from 'react';
function App_C(props) {
window.api.electronIpcOn('ping', (event, message) => {
console.log("App_C-window.api.electronIpcOn-ping-message: ", message)
})
window.api.electronIpcSend('pong', "Hello from App_C.tsx")
return (
<div id="outer-container" className='outer-container'>
<h1>App_C</h1>
</div>
);
}
export default App_C;
Executing the code, the page gets correctly rendered, but I do not see any message sent from the BrowserView to the renderer process.
Second, collateral, question, is: how to send a message on the way back, in the BrowserView sent by the renderer process?
And third question: how to interact with the page rendered by the BrowserView?
I'm building an app on electron and now I'm trying to create a simple file.
Here's the JS:
const app = require("electron").remote;
var dialog = app.dialog;
var fs = require("fs");
document.getElementById('save_project').onclick=() => {
dialog.showSaveDialog((filename) => {
if(filename === undefined){
console.log("You didnt save the file");
return;
};
var content = "hello there";
fs.writeFile(filename, content, (err) => {
if(err) console.log(err);
alert("The file has been successfully saved.")
})
});
};
This window will open as supposed:
Then, I wrote for instance: "hello.txt" on the name input and clicked save.
There's no log written on the console neither a file written in the directory
Edit:
with this js, happens the same ():
const fs = require("fs");
const {dialog} = require("electron").remote;
document.getElementById("save_project").addEventListener("click", () => {
dialog.showSaveDialog((filename) => {
if(filename === undefined){
console.log("nop");
return;
}
fs.writeFile(filename, content, (err) => {
if(err){
console.log(err);
return;
}
alert("file created");
});
});
}, false);
Edited:
Here's the createWindow()
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1920,
height: 1080,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
nodeIntegration: true
},
});
const childWindow = new BrowserWindow ({ width: 1600, height: 800, parent: mainWindow, modal: true, show : false});
// and load the index.html of the app.
mainWindow.loadFile("index.html");
childWindow.loadFile("welcome.html");
childWindow.once("ready-to-show", () => {
childWindow.show();
});
// Open the DevTools.
mainWindow.webContents.openDevTools();
}
Basically, from what i understood, "dialog.showSaveDialog((filename).." this was kinda blocking... i fixed by using:
const {dialog} = require("electron").remote;
let filename = dialog.showSaveDialogSync()
if(filename === undefined){
console.log("filename undefined");
return;
}else{
console.log(filename)
saveAsToFile(filename, ...);
}