URL smalltalk prompt not working with electron - javascript

sorry if this is a rookie question, but here it goes. Since electron doesn't support prompts I am trying to use [Smalltalk] (https://www.npmjs.com/package/smalltalk} to trigger one to insert an URL but it is not working, I have tried several options and still not working, here is the code:
// Insert Link //
const smalltalk = require('smalltalk');
function run(cmd, ele, value = null) {
let status = document.execCommand(cmd, true, value);
if (!status) {
switch (cmd) {
case 'insertLink':
smalltalk.prompt('Enter url')
.then((value) => {
console.log(value);
})
.catch(() => {
console.log('cancel');
});
if (value.slice(0, 4) != 'http') {
value = 'http://' + value;
}
document.execCommand('createLink', false, value);
// Overrides inherited attribute "contenteditable" from parent
// which would otherwise prevent anchor tag from being interacted with.
atag = document.getSelection().focusNode.parentNode;
atag.setAttribute("contenteditable", "false");
break;
}
}
}
Thanks in advance for your help!

in the end, I got it sorted by working with the 'insert link' functionality in javascript, as per this thread.
Clearly it was my limited knowledge of what was preventing me from getting this or other solutions to work on electron. It is all sorted now. Thanks again for your help and your time!

Related

(Edited) I am having an issue with my application not giving in-game currency

[Edited - Last time I forgot to add the code]
So i'm having an issue with my code not adding in-game currency to the user after they buy a product. All the internal testing and money work is well- the purchase goes through and the money is received. There is just an issue with adding the currency, which are in this case emblems, to the user. Unfortunately my friend wrote this code who no longer works on the project and I'm not very familiar with any of this, as I normally do UI stuff. Please let me know if I should upload any other images or provide any further information.
I'm not sure how far along it gets in the code before it breaks, but what I do know is using a button for testing and adding the same asyncstorage.getitem and setitem works when an onpress for a button. Again, I am very unfamiliar with all of this stuff so let me know what I need to provide to help.
This code works:
AsyncStorage.getItem('emblems').then(value =>{AsyncStorage.setItem('emblems', '10')})
This code doesn't work
<BuyBox Price='$0.99' EN='1 Emblem' onPress={async () => {
if (this.state.offerings != null) {
const pkg = this.state.offerings.emblems.availablePackages.find(offering => offering.identifier === 'ispy_1_emblems');
if (pkg) {
const {customerInfo, productIdentifier} = await Purchases.purchasePackage(pkg);
if (typeof customerInfo.entitlements.active.my_entitlement_identifier !== "undefined") {
console.log("purchase successful")
AsyncStorage.getItem('emblems').then(value => {
if (value == null){
AsyncStorage.setItem('emblems', '1');
} else {
AsyncStorage.setItem('emblems', (Number(value) + 1).toString());
}
})
}
}
}
}}/>
You forget to mention which library you using.
I'm guessing you're using Revenuecat react-native-purchases, you can print pkg in console to see many details including currency
const {customerInfo, productIdentifier} = await Purchases.purchasePackage(pkg);
use try to test it, I think it will giving error for the first time when there's no value on emblems
try {
const value = await AsyncStorage.getItem("emblems");
if (value !== null) {
AsyncStorage.setItem("emblems", (Number(value) + 1).toString());
} else {
//first time in
await AsyncStorage.setItem("emblems", "1"); //Set 1
}
} catch (e) {
// error reading value
await AsyncStorage.setItem("emblems", "1");
}

CHROME-EXTENSION: chrome.runtime.lastError no tab with id error

I am working on a project that creates a google chrome extension and I am using chrome API's in it. Now, I am trying to work my handleTabUpdate function when tab is updated. However, I am getting Unchecked runtime.lastError: No tab with id: 60
How can I fixed that? Here is my code:
chrome.tabs.onUpdated.addListener(handleTabUpdate)
function handleTabUpdate(tabId, info) {
if (info.status === 'loading') {
store.dispatch({ type: 'RESET_TABHOSTS' })
chrome.tabs.get(tabId, (activeTab) => {
if (tabId === store.getState().currentTab['id']) {
store.dispatch({ type: 'ACTIVE_TAB', payload: activeTab })
}
})
}
}
My guess is the tab you are looking for was closed, so when you try to get it by id the operation fails.
To avoid the error, my suggestion is to first query all tabs and see if a tab with a specific id exists in the result. If it does, run chrome.tabs.get() and with your logic.
Just bumped up against this issue in MV3 and I've tooled a solution that allows a bit more ease when working with tabs.
Functions
const handleRuntimeError = () => {
const error = chrome.runtime.lastError;
if (error) {
throw new Error(error);
}
};
const safeGetTab = async (tabId) => {
const tab = await chrome.tabs.get(parseInt(tabId));
try {
handleRuntimeError();
return tab;
} catch (e){
console.log('safeGetTab', e.message);
}
return {};
};
Implementation
(async () => {
// assumes some tabId
const tab = await safeGetTab(tabId);
})()
This will return a value no matter what. It will either return the tab object or an empty object. Then you can can just do some basic checking in your script to decide how you want to handle that. In my case I can simply ignore the action that would have been taken on that tab and move on.

ShowOpenDialog not working on recent versions of electron-js

I'm new on electronjs and developing a small application that reads a json file and build a small html form and return the values entered by the user.
So I've developed small scripts in javascript that link to html 'button' tags to call dialogs so that a user can enter directories, files and save the final form. Everything works nicely... on electronjs "^3.1.13". But if I'm updating to a recent version of the lib ("^8.2.5"), then all my cool ShowOpenDialog don't work at all. Any clue of what happens?
Here is the script to open a folder if it helps:
{
let myName = document.currentScript.getAttribute('name');
const ipc = require('electron').ipcRenderer;
let asyncBtn = document.querySelector('#folder-selector-'+myName);
let replyField = document.querySelector('#folder-selector-content-'+myName);
let onButtonClick = function() {
const { dialog } = require('electron').remote;
let dialogOptions = {
title: "Choisir un dossier:",
properties: ['openDirectory','promptToCreate'],
};
dialog.showOpenDialog(
dialogOptions,
fileNames => {
if (fileNames === undefined) {
console.log("No file selected");
} else {
console.log('file:', fileNames[0]);
replyField.value = fileNames[0];
}
})
};
asyncBtn.addEventListener("click", onButtonClick);
}
Thanks a lot for any help.
Apart from the fact that the call to dialog.showOpenDialog has indeed been updated in recent versions of Electron, and returns a promise instead of making use of a callback function, there is another flaw in your updated code: reading the above-mentioned documentation page shows that getCurrentWindow() is not a method of dialog; it can be obtained from remote instead, so you have to add it explicitely:
const { dialog, getCurrentWindow } = require('electron').remote;
then simply call it from inside dialog.showOpenDialog:
dialog.showOpenDialog( getCurrentWindow(), dialogOptions).then(result => {
but this is an error you could have caught yourself by looking at the DevTools's console, which would display:
TypeError: dialog.getCurrentWindow is not a function
Recent version of showOpenDialog receives two arguments: optional BrowserWindow, and options as second argument. It returns promise and not requires callback.
https://github.com/electron/electron/blob/8-x-y/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options
So you need to change you callback logic to promises.
let onButtonClick = function() {
const { dialog } = require('electron').remote;
let dialogOptions = {
title: "Choisir un dossier:",
properties: ['openDirectory','promptToCreate'],
};
dialog.showOpenDialog(
dialogOptions
).then((fileNames)=>{
if (fileNames === undefined) {
console.log("No file selected");
} else {
console.log('file:', fileNames[0]);
replyField.value = fileNames[0];
}
}).catch(err=>console.log('Handle Error',err))
};
asyncBtn.addEventListener("click", onButtonClick);
thanks a lot Vladimir. So I've tried to update my code as explained, updating electron package to version 8.2.5 and modifying the script as you explained but it's not going any better. If I got it well, this code should be correct, but doesn't work on electron 8.2.5. Any error you still see on this?
{
let myName = document.currentScript.getAttribute('name');
const ipc = require('electron').ipcRenderer;
let asyncBtn = document.querySelector('#folder-selector-'+myName);
let replyField = document.querySelector('#folder-selector-content-'+myName);
let onButtonClick = function() {
const { dialog } = require('electron').remote;
let dialogOptions = {
title: "Choisir un dossier:",
properties: ['openDirectory','promptToCreate']
};
dialog.showOpenDialog( dialog.getCurrentWindow(), dialogOptions).then(result => {
if(!result.canceled) {
replyField.value = result.filePaths[0];
}
}).catch(err => {
console.log(err)
})
};
asyncBtn.addEventListener("click", onButtonClick);
}
Ok, finally got it. Apart from the most appreciated help I had, I missed
"webPreferences": {
nodeIntegration: true
}
in the main.js to make it work.
The discovering of the Developer Tools were of great help as well :)
Now everything is fine again. Thanks a lot!

Add EventListener after inserting new HTML with plain Javascript

I recently began to code on a small frontend project in javascript. I came across the following problem:
Code Part 1
const startFeed = document.getElementById('startFeedButton');
const stopFeed = document.getElementById('stopFeedButton');
startFeed.addEventListener("click", () => {
api.streamingFunction(callback(response){
appendResponseToDom(response);
}
}
stopFeed.addEventListener("click", () => {
endStreamingFunction();
}
The 'api.streamingFunction' is part of a library and streams data via websocket. The 'callback' gets repeatedly called every time new data is available. It'll let you do something with the data inside the callback function. 'endStreamingFunction' closes the websocket.
Now the 'appendResponseToDom' function takes a piece of the data and appends it to the Dom like so:
Code Part 2
const someWhereInDom = document.getElementById('somewhere');
function appendResponseToDom(apiData) {
const newHTML = document.createElement("div");
newHTML.innerHTML = `
<div class="data">${apiData}</div>
<button id=${runningIndex}>Click here</button>
`
someWhereInDom.appendChild(newHTML);
}
Each button has a running index to uniquely select it. I didn't specify how runningIndex is evaluated in the code above.
What I want to do now is:
select every button uniquely after the newHTML has been inserted into the Dom (by adding event listeners) (and optionally in parallel stream new data via websocket)
Is this possible ? How would I usually do that ? Maybe you can point me in the right direction, thanks.
Solved it by observing changes in the Dom. See here: MutationObserver.
This article was also helpful: Detect, Undo And Redo DOM Changes With Mutation Observers
Solution Code
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if(mutation.target.nodeName === "BUTTON") {
mutation.target.addEventListener("click", () => {
console.log("clicked " + mutation.target.className); //Now, I can do sth with it!
})
}
});
});
mutationObserver.observe(someWhereInDom, {
attributes: true,
childList: true
});

How to properly close phantomjs webpage after use?

I'm trying to read some data from 200+ web pages with PhantomJS and typescript/rxjs
What I came up so far is this
Observable.fromPromise(phantom.createPage()).flatMap(jobPage => {
return Observable.fromPromise(jobPage.open(url)).flatMap(status => {
if (status !== "success") {
console.error("Couldn't load job page for url " + url + " Status: " + status);
jobPage.close();
return Observable.of(undefined)
} else {
return Observable.fromPromise(jobPage.evaluate(function () {
//do some content reading, return data
return data;
}));
}
});
})
And it works, but with every page it gets slower and slower, and finally ends with Memory Exhausted message from Phantom. I guess it's because I do not close the web pages I'm creating, but I dont have any idea how to do it such case (flatMap creates a new one, I need it for extraction later, and Observable.fromPromise() does not allow me to close the page after I'm done.
Any help is appreciated
Ok, figured it out, just need to use
Observable.fromPromise(phantom.createPage()).flatMap(jobPage => {
//stuff as before
}).finally(function(){
jobPage.close();
})

Categories