I am using Angular 2 with Electron. Here I added printing option in Electron's menu, but actually I want that not to add print option in Electron's menu. I want to add it in each page of HTML templates.
import { app, BrowserWindow, screen, Menu, webContents,} from 'electron';
import * as path from 'path';
let win, serve;
let contents = webContents;
const args = process.argv.slice(1);
serve = args.some(val => val === '--serve');
if (serve) {
require('electron-reload')(__dirname, {
});
}
const template = [
// {
// label: 'Edit',
// submenu: [
// {role: 'undo'},
// {role: 'redo'},
// {role: 'cut'},
// {role: 'copy'},
// {role: 'paste'},
// {role: 'pasteandmatchstyle'},
// {role: 'delete'},
// {role: 'selectall'}
// ]
// },
{
label: 'View',
submenu: [
{role: 'reload'},
{role: 'forcereload'},
{role: 'toggledevtools'},
{role: 'resetzoom'},
{role: 'zoomin'},
{role: 'zoomout'},
{role: 'togglefullscreen'}
]
},
// {
// role: 'window',
// submenu: [
// {role: 'minimize'},
// {role: 'close'}
// ]
// },
// {
// role: 'help',
// submenu: [ ]
// },
{
***
label: 'Print',
click () { win.webContents.print({silent: false, printBackground: false, deviceName: ''})}
***
},
// {
// label:'Drugs',
// submenu: [
// {
// label: 'Resus Drugs',
// click () {win.webContents.canGoForward()}
// },
// {
// label: 'Intubation',
// click () { }
// },
// {
// label: 'Arrythmias',
// click () { }
// },
// {
// label: 'Infusion',
// click () { }
// },
// {
// label: 'Fluids',
// click () { }
// },
// ]
// },
]
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
function createWindow() {
const electronScreen = screen;
const size = electronScreen.getPrimaryDisplay().workAreaSize;
// Create the browser window.
win = new BrowserWindow({
// frame:false,
backgroundColor: '#97b714',
x: 0,
y: 0,
width: size.width,
height: size.height
});
// and load the index.html of the app.
win.loadURL('file://' + __dirname + '/index.html');
// Open the DevTools.
// if (serve) {
// win.webContents.openDevTools();
// }
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store window
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
}
try {
// 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.on('ready', createWindow);
// 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();
}
});
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 (win === null) {
createWindow();
}
});
} catch (e) {
// Catch Error
// throw e;
}
Related
I am using quill editor and using a image handler for uploading images and it used to work fine but now i am moving to server side rendering and find this error of "File chooser dialog can only be shown with a user activation." while trying to open the file chooser for uploading the file.
imageHandler() {
//
let self=this
let image;
let image_extension;
var input = document.createElement("input");
// Set its type to file
input.type = "file";
// Set accept to the file types you want the user to select.
// Include both the file extension and the mime type
input.accept = "accept";
// set onchange event to call callback when user has selected file
input.addEventListener("change", onchange)
// dispatch a click event to open the file dialog
input.dispatchEvent(new MouseEvent("click")); //getting the error in this line.
input.onchange = async () => {
//
const file = input.files[0];
var ValidImageTypes = ["image/gif", "image/jpeg", "image/png", "image/jpg", "image/GIF", "image/JPEG", "image/PNG", "image/JPG"];
let file_type = file.type
let filename = file.name
let extension = filename.split('.').pop();
// debugger
if(ValidImageTypes.indexOf(file_type) >= 0){
if(file.size<=500000&&file.size>=50000){
// debugger
var fileToLoad = file
// loadImage(fileToLoad, (canvas) => {
// if(canvas){
// this.setState({
// image=canvas.toDataURL()
// image_extension=extension
// });
this.getBase64(file)
.then(result => {
// debugger
file["base64"] = result;
console.log("File Is",file.base64 );
const res = new Promise(function(resolve, reject) {
axios({
method:'post',
url:API_URL+'api/v1/postblogimage',
headers:{
'x-access-handler':loggedinUser.token
},
data:{
image: file.base64,
image_extension:image_extension,
userid:loggedinUser.userid
}
})
//axios.post(API_URL + 'api/v1/postblogimage', formData, config)
.then((response) => {
if (response.data.error == 'false' || response.data.error == false) {
if (response.data.status == 200 && response.data.message == "Image uploaded successfully") {
//
const range = self.quill.getSelection(true);
// Insert temporary loading placeholder image
// this.quill.insertEmbed(range.index, 'image', `${window.location.origin}/images/loaders/placeholder.gif`);
// Move cursor to right side of image (easier to continue typing)
self.quill.setSelection(range.index + 1);
// Remove placeholder image
self.quill.deleteText(range.index, 1);
// Insert uploaded image
let url=response.data.data[0].imageURL;
self.quill.insertEmbed(range.index, 'image', url);
self.quill.pasteHTML(range.index, <img src={url} class="blog-image-content" alt="Responsive image"/>);
}
}
// else if(response.data.error == 'true' || response.data.status == '500')
// componentProps.error('Sorry, Inappropriate image')
// }
}).catch((error) => {
// reject(Error("It broke"));
});
});
// }
// }, {orientation: true});
// }
})
}
else{
// componentProps.error(" Sorry, File size should be of size between 50 kb to 500kb")
}
}
else{
// this.setState({
// image_warning:'Invalid image type',
// image:'',
// image_extension:''
//})
// this.fileInput.value=''
}
};
}
//render function
<ReactQuill
ref={(el) => this.quillRef = el
}
onChange={this.handleChange}
placeholder={"You can insert images between your blog as well. Max image size to not exceed 500kb.Once you have uploaded an image, just wait, image will show up, if it is approved. Use #hashtags to highlight keywords/impact-terms in your blog, your blog might show up in trending keywords. Example: #gain"}
modules={{
toolbar: {
container: [
[{ header: '1' }, { header: [2,3, 4, 5, 6] }, { font: [] }],
[{ size: [ 'small', false, 'large', 'huge' ] }],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{ list: 'ordered' }, { list: 'bullet' }],
['link', 'image', 'video'],
['clean'],
['code-block'],
[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme
[{ 'align': [] }],
],
handlers: {
image: this.imageHandler
}
}
}}
/>
Before you click you must add the input to the document body
document.body.appendChild(input);
I am writing a chrome extension that makes requests to an API and I have noticed that after I create a notification from background script using chrome's notification API, the listeners on the buttons from the notification are executed multiple times. on the first run only once and then increasing. I figured that the listeners just add up on the page but I couldn't find a way to sort of refresh the background page.
This is the function that creates the notification and it's listeners.
var myNotificationID
const displayNotification=(userEmail, password, website,username) =>{
chrome.notifications.create("", {
type: "basic",
iconUrl: "./icon128.png",
title: "PERMISSION",
requireInteraction: true,
message: "question",
buttons: [{
title: "YES",
}, {
title: "NO",
}]
}, function(id) {
myNotificationID = id;
})
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (notifId === myNotificationID) {
if (btnIdx === 0) {
console.log('inserting')
try{
fetch (`http://localhost:8080/users/${userEmail}/accounts`,{
})
}catch(err){
}
} else if (btnIdx === 1) {
console.log('clearing')
chrome.notifications.clear(myNotificationID)
}
}
});
}
And this is where the function is called
chrome.runtime.onMessage.addListener((message, sender, response)=>{
if(message.message === 'showNotification'){
console.log('received insert')
displayNotification(message.userEmail,message.password, message.currentSite,message.username)
response({status:"received"})
}
})
the fetch within the listener is executed multiple times but the log from the onMessage listener is only displayed once, so the listener is the problem here.
I tried chrome.notifications.onButtonClicked.removeListener(), but as i mentioned there was no success.
Are there any other ways in which i could clean the listeners from the background script once they are used?
Using a notification store:
const notificationsByID = {};
chrome.notifications.onButtonClicked.addListener((notifId, btnIdx) => {
// Avoid access to the notification if not registered by displayNotification
if (!notificationsByID[ notifId ]) { return null; }
if (btnIdx === 0) {
console.log('inserting')
try{
fetch (`http://localhost:8080/users/${ notificationsByID[ notifId ].userEmail }/accounts`,{ /**/ });
}catch(err){
console.log(err);
}
delete notificationsByID[ notifId ]; // Cleanup
} else if (btnIdx === 1) {
console.log('clearing')
chrome.notifications.clear(myNotificationID);
delete notificationsByID[ notifId ]; // Cleanup
}
});
chrome.notifications.onClosed.addListener((notifId) => {
if (notificationsByID[ notifId ]) { delete notificationsByID[ notifId ]; }
});
const displayNotification=(userEmail, password, website,username) =>{
chrome.notifications.create("", {
type: "basic",
iconUrl: "./icon128.png",
title: "PERMISSION",
requireInteraction: true,
message: "question",
buttons: [{ title: "YES", }, { title: "NO", }]
}, function(id) {
// Insertion
notificationsByID[ id ] = { userEmail, password, website,username };
})
}
When trying to open the window from the menu, an error like this comes up: "Attemping to call a function in a renderer window that has been closed or released", but the other windows are called without any problem.
const ventana = document.getElementById("ventana");
const contrasena = document.getElementById("contra");
const remote = require("electron").remote;
const Menu = remote.Menu;
const BrowserWindow = remote.BrowserWindow;
const url = require("url");
const path = require("path");
let secundario
let recuperaVentana
let add
ventana.addEventListener("click", () => {
var usuario = document.getElementById("user").value;
var pass = document.getElementById("pass").value;
if(usuario != "" & pass != ""){
createBrowserWindow();
} else {
alert("No ha llenado los campos");
}
});
contrasena.addEventListener("click", () => {
recuperarBrowserWindow();
})
function createBrowserWindow() {
secundario = new BrowserWindow({
height: 600,
width: 800
});
secundario.loadURL(url.format({
pathname: path.join(__dirname, "./prefs.html"),
protocol: "file",
slashes: true
}));
//secundario.webContents.openDevTools();
//menu
const menuSec = Menu.buildFromTemplate(templateMenu);
Menu.setApplicationMenu(menuSec);
cerrar();
}
function recuperarBrowserWindow(){
recuperaVentana = new BrowserWindow ({
title: "Recuperar"
})
recuperaVentana.loadURL(url.format({
pathname: path.join(__dirname, "./recuperar.html"),
protocol: "file",
slashes: true
}))
recuperaVentana.setMenu(null);
}
//cerrando ventana
function cerrar(){
window.close();
}
//creando menus
const templateMenu = [
{
label: "Archivo",
submenu: [
{
label: "Nuevo",
accelerator: "Ctrl+N",
click(){
addBrowserWindow();
}
},
{
label: "Abrir",
accelerator: "Ctrl+O"
},
{
label:"Guardar",
accelerator:"Ctrl+G"
},
{
type: "separator"
},
{
label:"Salir"
}
]
},
{
label: "Ayuda"
}
];
function addBrowserWindow() {
add = new BrowserWindow({
title: "Agregar"
})
add.loadURL(url.format({
pathname: path.join(__dirname, "./agregar.html"),
protocol: "file",
slashes: true
}))
}
When trying to call the function "addBrowserWindow()" the above mentioned error is shown
This is a fairly concise version of code that creates a second window on selecting a submenu:
const electron = require('electron')
const { app, BrowserWindow, Menu } = electron
let mainWindow
let secondWindow
app.on('ready', () => {
console.log('Starting Node version: ' + process.version)
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: true,
},
})
mainWindow.loadURL(`file://${__dirname}/main.html`)
mainWindow.on('closed', () => app.quit())
const mainMenu = Menu.buildFromTemplate(menuTemplate)
Menu.setApplicationMenu(mainMenu)
})
function createSecondWindow() {
secondWindow = new BrowserWindow({
width: 300,
height: 200,
title: 'Add New Todo',
})
secondWindow.loadURL(`file://${__dirname}/add.html`)
}
const menuTemplate = [
{
label: 'File',
submenu: [
{
label: 'New ToDo',
click() {
createSecondWindow()
},
},
{
label: 'Quit',
accelerator: process.platform === 'darwin' ? 'Command+Q' : 'Ctrl+Q',
click() {
app.quit()
},
},
],
},
]
if (process.platform === 'darwin') {
menuTemplate.unshift({})
}
Note that by default when you close the main window and the second window will still be present - which is weird behaviour rarely needed. The solution to that is to ensure you call app.exit() when the main window is closed.
I am working on an about this app window on Windows and I want to make a custom menu bar for my about window. Since I already have a custom menu is there a way I can create another one and apply it only to that specific window?
Side note:
Here is my code for the new window that is supposed to stop it from being adjusted and going into full screen, but for some reason the minimize and enlarge button still work.
app.on('ready', createWindow);
electron.app.on('ready', () => {
//Triger update check
if (!isDev) {
autoUpdater.checkForUpdates();
}
})
function createWindow(){
//create brower window
win = new BrowserWindow({
backgroundColor: '#2e2c29',
width: 800,
height: 600,
//transparent: true,
frame: false,
titleBarStyle: 'hidden',
backgroundColor: '#0000',
webPreferences: {
nodeIntegration: true
}
});
//Quit when all windows are closed
app.on('window-all-closed', () => {
app.quit()
})
app.once('ready', function() {
const template = [
{
label: 'File',
submenu: [
{
label: 'About Hubris',
click: () =>
openAboutWindow()
},
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
},
{
label: 'View',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
]
},
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
//here is the code for the about window
var newWindow = null
function openAboutWindow() {
if (newWindow) {
newWindow.focus()
return
}
newWindow = new BrowserWindow({
height: 439,
resizable: false,
width: 599,
title: 'About Hubris',
minimizable: false,
fullscreenable: false,
frame: false,
titleBarStyle: 'hidden',
})
newWindow.loadURL('file://' + __dirname + '/about-this-app.html')
newWindow.on('closed', function() {
newWindow = null
})
}
});
You can switch menus on the fly. I have an app with 'editor' and 'presentation' modes. I create and store a menu for each mode (they have different menu items):
let editorMenu = Menu.buildFromTemplate(menuTemplate);
and subscribe to the relevant window events (focus, blur, etc). Then when a window gets focus
Menu.setApplicationMenu(editorMenu);
To do this, you have to import menu from electron in at the top of our main.js file:
// From
const {app, BrowserWindow} = require('electron')
// To
const {app, BrowserWindow, Menu} = require('electron').
Then, near the bottom of our createWindow() function, we add:
function createWindow () {
// some code here removed for brevity
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'Adjust Notification Value'},
{label:'CoinMarketCap'},
{label:'Exit'}
]
}
])
Menu.setApplicationMenu(menu);
}
Next, we reference Menu.buildFromTemplate([{}]), which is where our menu is actually defined and built, within a series of arrays and objects.
The "label" represents the name you want your menu to display so put what you like.
The "submenu" property is an array of objects, with each object defining the actual menu items displayed when the label is clicked.
Finally, use .setApplicationMenu to set the menu. If you save the project, and run npm start in the console, you will see the menu with it's items (array) being displayed but if your click on them nothing happens.
You can change this by going back to our main.js, add the following code to make our Exit button close the application:
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'Adjust Notification Value'},
{label:'CoinMarketCap'},
{
label:'Exit',
click() {
app.quit()
}
}
]
}
])
So, to make a menu item clickable, we simply add a comma after the label value, and reference "click() { }"
In this case, we're calling app.quit()" when the Exit submenu item is clicked. Give it a try by running npm start in the console and click Exit.
That's it!
I'm in the process of finishing up my first app on Electron, i'm a Junior Web Developer, so please excuse me if it's a simple mistake or you spot something you think can be done better. But basically, I'm building a basic menu on macOS so I can have Copy / Paste functionality after packaging. Now i've followed the documentation from https://github.com/electron/electron/blob/master/docs/api/menu.md, made a few tweaks to fit my needs but seem to be having a problem when running, the error being:
Uncaught Exception:
TypeError: Cannot read property 'buildFromTemplate' of undefined
at EventEmitter.createWindow (/Users/Jay/Desktop/click_palette_release/app/main.js:73:22)
at emitOne (events.js:101:20)
at EventEmitter.emit (events.js:188:7)
This to me would suggest that 'template' isn't defined? However I define it at the top on line 70 with const. What am I missing here? Been scratching my head at it for some time now.
const template = [
{
label: 'Edit',
submenu: [
{
role: 'copy'
},
{
role: 'paste'
},
]
}];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
Line 73 being const menu = Menu.buildFromTemplate(template);
Thanks in advance!
Full code:
const electron = require('electron');
const {app} = electron;
const {BrowserWindow} = electron;
const Configstore = require('configstore');
const pkg = require(__dirname + '/init.json');
const sysconf = new Configstore(pkg.name);
var Menu = require("electron").menu;
let mainWindow;
function createWindow(){
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
if (sysconf.get('bounds')){
var bounds = sysconf.get('bounds');
} else {
var bounds = {'x':'', 'y':'', 'width':'400', 'height':'125'}
}
// Create the browser window.
mainWindow = new BrowserWindow({
x: bounds.x,
y: bounds.y,
width: 400,
height: 90,
//'titleBarStyle': 'hidden',
title: 'ClickPalette',
backgroundColor: '#fff',
frame: false
});
mainWindow.setResizable(false);
mainWindow.setAlwaysOnTop(true);
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.setMenu(null);
//mainWindow.webContents.openDevTools();
mainWindow.on('close', function(e) {
var bounds = mainWindow.getBounds();
sysconf.set({'bounds' : bounds});
});
// Emitted when the window is closed.
mainWindow.on('closed', function() {
mainWindow = null;
});
//Settings / Manager
var manageWindow = new BrowserWindow({
width: 400,
height: 400,
show: false
});
manageWindow.loadURL('file://' + __dirname + '/manage.html');
//manageWindow.webContents.openDevTools();
const template = [
{
label: 'Edit',
submenu: [
{
role: 'copy'
},
{
role: 'paste'
},
]
}];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
};
// Load mainWindow
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit();
}
});
//Show window
app.on('activate', function (e) {
if (mainWindow === null) {
createWindow();
}
});
RESOLVED
I was using const Menu = require('electron').menu; but the M in menu should have been uppercase: const Menu = require('electron').Menu;