I am using Electron ,I have made a custom titlebar with a div which unhides 2 divs,
I want one of these divs(labeld "open") to open a file manager
This can be done using shell.showItemInFolder(--dirname);But the problem is that i cannot retrieve any data from this method , another way is to use Dialog in electron const{dialog} = require('electron');
I treid is to write this console.log(dialog.openShowDialog({properties:['openFile']}));
This (according to some youtube videos i watched) should open a file manager and if i select a file through this , it should log a pending promise.But i get an errorcannot get the property 'showOpenDialog'of undefined
const{dialog} = require('electron');
function openFS(){
win.openDevTools();
console.log(dialog.showOpenDialog({properties:['openFile']}));
}
This openFS function is called on the click of the div mentioned above.
How do i get around?
cannot get the property 'showOpenDialog'of undefined
That error indicates that dialog is undefined. If you are executing this code in the render process, then you are not importing the dialog module correctly – it needs to be accessed through remote (assuming you have specified nodeIntegration: true for the renderer). Personally, I handle all dialog calls in the main process but that's a matter of choice.
const {dialog} = require('electron').remote
HOWEVER . . the remote module is deprecated in Electron 12 as the linked doc indicates. I haven't yet used the method it recommends so I can't speak to any issues with that.
The remote module is deprecated in Electron 12, and will be removed in
Electron 14. It is replaced by the #electron/remote module.
// Deprecated in Electron 12:
const { BrowserWindow } = require('electron').remote
// Replace with:
const { BrowserWindow } = require('#electron/remote')
// In the main process:
require('#electron/remote/main').initialize()
Related
I am trying to build a chrome://offline-internals/ functionality. The chrome://offline-internals/ shows among many things, the pages which are stored for offline viewing, and this feature are only available in mobile chrome browser.
The page at chrome://offline-internals/ basically has a HTML page which I found using view-source:chrome://offline-internals/. I the HTML a javascript is referenced (offline_internals.js), which in turn has nested javascript referenced. I downloaded all referenced javascript in my local folder since chrome doesn't allow access to chrome://resources/js for referencing js pages.
After downloading, I tried to open HTML page and I got an error as below
cr.m.js:107 Uncaught TypeError: chrome.send is not a function
at sendWithPromise (cr.m.js:107)
at OfflineInternalsBrowserProxyImpl.getStoredPages (offline_internals_browser_proxy.js:30)
at refreshAll (offline_internals.js:64)
at HTMLDocument.initialize (offline_internals.js:248)
This basically comes in a file called cr.m.js in the below function
export function sendWithPromise(methodName, var_args) {
const args = Array.prototype.slice.call(arguments, 1);
const promiseResolver = new PromiseResolver();
const id = methodName + '_' + createUid();
chromeSendResolverMap[id] = promiseResolver;
chrome.send(methodName, [id].concat(args)); <-- Error
return promiseResolver.promise;
}
I tried to open chrome://offline-internals/ and set my breakpoint at the above function and that time chrome.send was found to be a function and when I ran my custom HTML page having same source and references, it says chrome.send is not a function.
Probably, the chrome instance given to my script vis-a-vis the one given to chrome://offline-internals/ is a different one.
What can I do to resolve this issue ?
P.S.: This link chrome://offline-internals/ will open in your mobile chrome browser only.
P.S.: All downloaded files are present at this path, in case you wish to see:
https://easyupload.io/9x332s
Does the Electron application framework have built-in text search?
The quick-start application doesn't provide any apparent search functionality (e.g. using Ctrl-F or from the menu options). I would have expected this to be a BrowserWindow option (or an option of its WebContents), but I don't see anything helpful in the docs.
I know this is an old thread, but might still be relevant for people out there.
Had the same problem, and first fixed by using electron-in-page-search, but this component doesn't work properly with Electron 2 or greater.
Then finally found electron-find resolved my problem. Using with Electron 4.
You just add the component to your project:
npm install electron-find --save
Add a global shortcut in your Electron main process to send an event to the renderer in a ctrl+f:
globalShortcut.register('CommandOrControl+F', () => {
window.webContents.send('on-find');
});
And then you can add this to your page (the renderer process)
const remote = require('electron').remote;
const FindInPage = require('electron-find').FindInPage;
let findInPage = new FindInPage(remote.getCurrentWebContents());
ipcRenderer.on('on-find', (e, args) => {
findInPage.openFindWindow()
})
Hope that helps.
Try webContents.findInPage just added in the latest version.
There is an issue with the solution Robson Hermes offered. globalShortcut is, by definition, global, so the shortcut will be detected even when the app is not focused. This will result in the Ctrl+F shortcut being "stolen" from everywhere else.
I have found no ideal solution (see this issue on the electron repository), but a hacky one can be achieved by doing what Robson said and adding
win.on('focus', () => {
globalShortcut.register('CommandOrControl+F', () => windows.main.send('on-find'))
})
win.on('blur', () => {
globalShortcut.unregister('CommandOrControl+F')
}
Note that as seen here, this is not ideal and can lead to several issues:
Other applications can get a lock on the shortcut when you lose focus, i.e. the shortcut will magically stop working when you switch back to the app later.
Some apps can appear on screen without taking focus (spotlight I believe has this behavior) and during the app's appearance the shortcuts will still be captured by your application.
There's also gonna be those weird one in a thousand situations where somehow you switch focus and the shortcut is not removed.
Instead of using global shortcuts , use Accelerators ( normal Keyboard shortcut )
{
label : 'help',
click : function(){.
electron.shell.openExternal('http://....').
},
accelerator : 'CmdOrCtrl+ Shift + H'
}
The above shown is just an example of How to use accelerator
Whilst this question is related to Workbox and Webpack, it does not require any prior knowledge of either library.
Background (skip if not familiar with Workbox)
I am currently utilising the InjectManifest plugin from Workbox 4.3.1 (workbox-webpack-plugin). This version of the library offers an option called manifestTransforms, but unfortunately, the transformations are not applied to assets within the webpack compilation (this is a known issue).
Whilst this has been fixed in Workbox v5+, I am unable to upgrade due to another library in my build process requiring webpack v3 (Dynamic Importing in Laravel Mix)
The reason I mention the above is because unforunately the solution is not to upgrade to workbox v5+.
The Problem
I have an auto-generated file that looks like this:
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "68cd3870a6400d76a16c",
"url": "//css/app.css"
},
// etc...
]);
I need to somehow extract the the contents of the object stored within self.__precacheManifest, apply my own transformations, and then save it back to the file.
What I have Tried...
This is as far as I have got:
// As the precached filename is hashed, we need to read the
// directory in order to find the filename. Assuming there
// are no other files called `precache-manifest`, we can assume
// it is the first value in the filtered array. There is no
// need to test if [0] has a value because if it doesn't
// this needs to throw an error
let manifest = fs
.readdirSync(path.normalize(`${__dirname}/dist/js`))
.filter(filename => filename.startsWith('precache-manifest'))[0];
require('./dist/js/' + manifest);
// This does not fire because of thrown error...
console.log(self.__precacheManifest);
This throws the following error:
self is not defined
I understand why it is throwing the error, but I have no idea how I am going to get around this because I need to somehow read the contents of the file in order to extract the object. Can anyone advise me here?
Bear in mind that once I have applied the transformations to the object, I then need to save the updated object to the file...
Since self refers to window and window does not exist in node.js a way around is needed.
One thing that should work is to define the variable self in Node's global scope and let the require statement populate the content of the variable, like this:
global['self'] = {};
require('./dist/js/' + manifest);
console.log(self.__precacheManifest);
To save the modified contents back to the file
const newPrecacheManifest = JSON.stringify(updatedArray);
fs.writeFileSync('./dist/js/' + manifest, `self.__precacheManifest = (self.__precacheManifest || []).concat(${newPrecachedManifes});`, 'utf8');
I'm just getting started with Electron, with prior experience with node-webkit (nw.js).
In nw.js, I was able to create iframes and then access the DOM of said iframe in order to grab things like the title, favicon, &c. When I picked up Electron a few days ago to port my nw.js app to it, I saw advice to use webviews instead of iframes, simply because they were better. Now, the functionality I mentioned above was relatively easy to do in nw.js, but I don't know how to do it in Electron (and examples are slim to none). Can anyone help?
Also, I have back/forward buttons for my webview (and I intend on having more than one). I saw in the documentation that I could call functions for doing so on a webview, but nothing I have tried worked either (and, I haven't found examples of them being used in the wild).
I dunno who voted to close my question, but I'm glad it didn't go through. Other people have this question elsewhere online too. I also explained what I wanted to achieve, but w/e.
I ended up using ipc-message. The documentation could use more examples/explanations for the layperson, but hey, I figured it out. My code is here and here, but I will also post examples below should my code disappear for whatever reason.
This code is in aries.js, and this file is included in the main renderer page, which is index.html.
var ipc = require("ipc");
var webview = document.getElementsByClassName("tabs-pane active")[0];
webview.addEventListener("ipc-message", function (e) {
if (e.channel === "window-data") {
// console.log(e.args[0]);
$(".tab.active .tab-favicon").attr("src", e.args[0].favicon);
$(".tab.active .tab-title").html(e.args[0].title);
$("#url-bar").val(e.args[0].url);
$("#aries-titlebar h1").html("Aries | " + e.args[0].title);
}
// TODO
// Make this better...cancel out setTimeout?
var timer;
if (e.channel === "mouseover-href") {
// console.log(e.args[0]);
$(".linker").html(e.args[0]).stop().addClass("active");
clearTimeout(timer);
timer = setTimeout(function () {
$(".linker").stop().removeClass("active");
}, 1500);
}
});
This next bit of code is in browser.js, and this file gets injected into my <webview>.
var ipc = require("ipc");
document.addEventListener("mouseover", function (e) {
var hoveredEl = e.target;
if (hoveredEl.tagName !== "A") {
return;
}
ipc.sendToHost("mouseover-href", hoveredEl.href);
});
document.addEventListener("DOMContentLoaded", function () {
var data = {
"title": document.title,
"url": window.location.href,
// need to make my own version, can't rely on Google forever
// maybe have this URL fetcher hosted on hikar.io?
"favicon": "https://www.google.com/s2/favicons?domain=" + window.location.href
};
ipc.sendToHost("window-data", data);
});
I haven't found a reliable way to inject jQuery into <webview>s, and I probably shouldn't because the page I would be injecting might already have it (in case you're wondering why my main code is jQuery, but there's also regular JavaScript).
Besides guest to host IPC calls as NetOperatorWibby, it is also very useful to go from host to guest. The only way to do this at present is to use the <webview>.executeJavaScript(code, userGesture). This api is a bit crude but it works.
If you are working with a remote guest, like "extending" a third party web page, you can also utilize webview preload attribute which executes your custom script before any other scripts are run on the page. Just note that the preload api, for security reasons, will nuke any functions that are created in the root namespace of your custom JS file when your custom script finishes, however this custodial process will not nuke any objects you declare in the root. So if you want your custom functions to persist, bundle them into a singleton object and your custom APIs will persist after the page fully loads.
[update] Here is a simple example that I just finished writing: Electron-Webview-Host-to-Guest-RPC-Sample
This relates to previous answer (I am not allowed to comment): Important info regarding ipc module for users of Electron 1.x:
The ipc module was split into two separate modules:
ipcMain for the main process
ipcRenderer for the renderer process
So, the above examples need to be corrected, instead of
// Outdated - doesn't work in 1.x
var ipc = require("ipc");
use:
// In main process.
var ipcMain = require('electron').ipcMain
And:
// In renderer process.
var ipcRenderer = require('electron').ipcRenderer
See: http://electron.atom.io/blog/2015/11/17/electron-api-changes section on 'Splitting the ipc module'
I'm trying to port my Firefox extension to work under Electrolysis / e10s / multi-process mode. I've got a feature that requires registration through nsIComponentRegistrar so it's in a JSM which gets loaded only once (per process). I'm running in the child scope, so I don't have access to things like files, but my feature requires that. So I want to sendSyncMessage() to the parent process to fetch that detail (just the path to a file in this case).
The docs even mention doing something like this explicitly. But in the JSM I don't have a message manager in scope to call sendSyncMessage() on. How do I get a handle to (the right?) one? When I get called I don't have anything relating to the content document/window in scope.
Update, for clarity:
var c = Cc['#mozilla.org/childprocessmessagemanager;1'];
var s = c.getService(Ci.nsISyncMessageSender);
var response = s.sendSyncMessage('id', {'data': 'x'});
dump('response len?? ' + response.length + '\n');
This code produces 0 responses, even running directly in the frame script (not in the JSM which the frame script loads). If I just use the globally available sendSyncMessage() in the frame script then it gets the 1 response I expect.
"#mozilla.org/childprocessmessagemanager;1" is the way to go. Use that in child process JSMs.
However, as MDN puts it:
In addition to Message Managers centered around window and tab objects
there also is a separate hierachy focusing on process boundaries.
Therefore, you cannot use the regular frame script messengers, but have to use "#mozilla.org/parentprocessmessagemanager;1" in the parent (main) process.
child.jsm
let cpmm = Cc["#mozilla.org/childprocessmessagemanager;1"].
getService(Ci.nsISyncMessageSender);
cpmm.sendSyncMessage("addon:present?!")[0] === "yup"
parent.jsm
let ppmm = Cc["#mozilla.org/parentprocessmessagemanager;1"].
getService(Ci.nsIMessageListenerManager);
ppmm.addMessageListener("addon:present?", m => "yup");
Core code uses this scheme in various places, e.g. Network:SampleRate
This may work, no promises.
Try loading:
Cc["#mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
If that doesn't work then try using:
Cc['#mozilla.org/childprocessmessagemanager;1'].getService(Ci.nsISyncMessageSender);
Or vice-versa