Reputation: 123
So I'm working on a new project and we would like to create a desktop application for our users using Electron.
The problem is that I need custom contextmenus on the webview elements.
My progress so far that I can create contextmenus over the webview, but I cannot access the content under the click. :)
index.html:
<webview id="webViewDefault" class="active" src="http://example.com" minwidth="100%" minheight="100%" partition="somePartition" nodeintegration allowpopups></webview>
renderer.js
const electron = require('electron');
const Menu = electron.remote.Menu;
//Create contextmenu template
const WebViewMenu = Menu.buildFromTemplate([{
label: 'Button 1', click(){
console.log('Button 1 clicked');
}
},
{type: 'separator'}, {
label: 'Button 2', click(){
console.log('Button 2 clicked');
}
}
]);
//get webview
let defaultWebview = document.getElementById("webViewDefault");
//add event listner
defaultWebview.addEventListener("contextmenu", (event) => {
const t = event.srcElement.id.split('-');
WebViewMenu.popup(electron.remote.getCurrentWindow());
});
So how can I get for example a link's href
attribute when a right click happens, so I can create a new tab for the user.
The tabs are working great, creating new webviews, selecting the active ones etc. I just need to get the urls, from the links ...: D
Upvotes: 2
Views: 3946
Reputation: 148
Store your desired information in a global state store, and then access it from within your context menu click event.
For Example
// Instantiate a Global Store
const globalStore = {
eventTargetHref = null
}
// Set value inside your DOM node event listener
aDOMnode.addEventListener('contextmenu', (event) => {
event.preventDefault()
globalStore.eventTargetHref = event.target.href
aContextMenu.popup(remote.getCurrentWindow())
}
// Access value from your context menu click event
aContextMenu.append(new MenuItem({
label: 'Open In New Tab',
click() {
addNewTab(globalStore.eventTargetHref)
},
}))
Upvotes: 5
Reputation: 123
Okay I figured it out, so I'm going to answer my question.
My solution for the problem is the webview's preload attribute. I created a *.js file which is injected in to the webview on load. This file contains the event listeners for the click events and sends an "ipc" message based on the events target via the "ipcRenderer" in electron to the main window.
This way I can create different contextmenus for different elemnts e.g: a, input, textarea etc...
Injected js:
const {ipcRenderer} = require('electron');
document.addEventListener('contextmenu', function (e) {
e = e || window.event;
let msg = {
tagName: e.target.tagName || e.srcElement.tagName,
text: e.target.textContent || text.innerText,
href: e.target.getAttribute("href")
};
if (msg.tagName.toLowerCase() === 'a' && msg.href.substring(0, 1) !== "#") {
ipcRenderer.send("webview-context-link", msg);
}
}, false);
In the webview's parent window I listen for my custom ipc messages and handle them as needed:
const electron = require('electron'),
Menu = electron.remote.Menu,
ipc = electron.ipcRenderer;
electron.remote.ipcMain.on("webview-context-link", (event, data) => {
if (url = validateUrl(data.href)) {
const WebViewMenu = Menu.buildFromTemplate([{
label: 'Open in new tab', click(){
addNewTab(url)
}
}]);
WebViewMenu.popup(electron.remote.getCurrentWindow());
}
});
I'm not 100% sure this is the nicest way to solve this issue, but for the time being it work if I come up with a better solution I'll edit this.
Upvotes: 5