I'm using Electron with React+Typescript but this can be tested using just Electron+Javascript. The dom-ready event is working, I can see it in the console, but the contextmenu event is not triggered when I right click.
export default Main() {
const browserRef = useRef<WebViewProps>(null);
useEffect(() => {
const domReady = () => {
console.log("Dom is ready!");
};
const contextMenu = () => {
console.log("Context menu is working!");
};
if(browserRef.current) {
browserRef.current.addEventListener("dom-ready", domReady);
browserRef.current.addEventListener("contextmenu", contextMenu);
};
return () => {
if (browserRef.current) {
browserRef.current?.removeEventListener("dom-ready", domReady);
browserRef.current?.removeEventListener("contextmenu", contextMenu);
};
};
}, []);
return (
<webview ref={browserRef} src="https://www.google.com/" />
);
};
My contextmenu is not being called when I right click, this makes me think it doesn't fire when I right click but i don't know...
Related
With the new electron, event 'new-window' is deprecated and replaced with BrowserContent.setWindowOpenHandler.
How to setup various events, including dom-ready for opening devtools?
app.on('ready', () => {
mainWindow = createMainWindow();
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
// Set event listener on to-be-created WebContent
// { ..., overrideBrowserWindowOptions: { events, enableDevTools: true, etc } }
return { action: 'allow' };
});
});
You'd need to additionally intercept the did-create-window event which fires when the window is created:
mainWindow.webContents.on("did-create-window", (window, details) => {
window.webContents.once("dom-ready", () => window.webContents.openDevTools());
});
I have a website where I have various notes for my classes. These notes are in pdfs and the structure of my website is like this: /year_1/class_1/notes.pdf.
I'm trying to use electron to make a desktop application for viewing my notes and I'm using PDFwindow because electron can't open pdfs otherwise.
However, when I try to go to class_1.html, I get this error: https://i.imgur.com/Nj5GGjD.png
Here is my code and I'm using electron version 18.0.3 and electron-pdf-window version 1.0.12.
const { app, BrowserWindow, Tray, Menu } = require("electron");
const PDFWindow = require("electron-pdf-window");
app.on("ready", () => {
const mainWindow = new PDFWindow({
title: "title",
});
mainWindow.maximize();
mainWindow.show();
mainWindow.on("minimize", function (event) {
event.preventDefault();
mainWindow.hide();
});
mainWindow.on("close", function (event) {
if (!app.isQuiting) {
event.preventDefault();
mainWindow.hide();
}
return false;
});
mainWindow.loadURL("link/to/my/site");
let tray = new Tray("/some/pic");
const contextMenu = Menu.buildFromTemplate([
{
label: "Show App",
click: () => {
mainWindow.show();
},
},
{
label: "Quit",
click: () => {
app.isQuiting = true;
app.quit();
},
},
]);
tray.setContextMenu(contextMenu);
});
Thank you
I am using React button with child components that change based on the state like, is button pressed, touched etc. I have defined custom event handlers that change the states, isPressed, isTouched etc.
Issue: On iPhone , the onTouchEnd is not firing. With, iOS voiceover turned ON the issue is more prominent because mouse events are not fired. So the user has to tap-tap twice to actually click succeed.
Here are the events -->
const onMouseDown = function(){
setPressed(true);
};
const onMouseUp = function(){
handleClick();
}
const onTouchStart = function(){
setTouched(true);
setHover(false);
setPressed(true);
};
const onKeyDown = function(keyboardEvent: any){
if (keyboardEvent.key === "Enter") {
handleClick();
};
};
const onTouchMove = function(e: any){
e.preventDefault();
};
const onTouchEnd = function(e: any) {
e.preventDefault();
setTouched(false);
setHover(false);
if (!clicked) {
handleClick();
}
};
const onFocus = function () {
if (!touched) {
setHover(true);
}
};
const onKeyUp = function(keyboardEvent: any) {
if (keyboardEvent.key === "Enter") {
handleClick();
}
};
const onBlur = function() {
setHover(false);
setPressed(false);
};
const onMouseOver = function () {
if (!touched) {
setHover(true);
}
};
const onMouseOut = function () {
setHover(false);
setPressed(false);
}
This is the button content -
<button
style={buttonStyle}
onMouseDown={onMouseDownf}
onMouseUp={onMouseUp}
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
onMouseOver={onMouseOver}
onFocus={onFocus}
onMouseOut={onMouseOut}
onBlur={onBlur}
onTouchStart={onTouchStart}
onTouchCancel={onTouchCancel}
onTouchMove={onTouchMove}
onTouchEnd={onTouchEnd}
onClick={() => { console.log("onClick") }}
disabled={props.disabled}
>
{
pressed ? <Spinner styles={newSpinnerStyle} size={SpinnerSize.large} /> : normalButtonContent
}
</button>
</>
If I remove the dynamic content it works fine, i.e. -->
{ pressed ? <Spinner styles={newSpinnerStyle} size={SpinnerSize.large} /> : normalButtonContent }
to
{ normalButtonContent }
Looks like when the child component changes, the button (i.e. the parent) is re-rendered. And so the onTouchEnd is not fired. Probably a race condition between the re-render and onTouchEnd call.
Moving the dynamic component i.e. spinner / normalButtonContent outside of the button helped workaround this issue.
On App.js I have initialized AdMobRewarded as following:
if (Platform.OS === 'ios') {
AdMobRewarded.setAdUnitID('ca-app-pub-xxx/xxx');
} else {
AdMobRewarded.setAdUnitID('ca-app-pub-xxx/xxx');
}
And here is the class:
export default class App extends React.Component {
state = {
fontsLoaded: false,
};
render() {
const { fontsLoaded } = this.state;
if (!fontsLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => this.setState({ fontsLoaded: true })}
/>
);
}
return (
<Provider store={store}>
<AppContainer
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
<CommonComponents />
</Provider>
);
}
}
Inside the CommonComponents I have put the listener for AdMobRewarded:
useEffect(() => {
AdMobRewarded.addEventListener('rewardedVideoDidRewardUser', () => {
setState({
hintModalVisible: true,
adIsLoading: false,
mainMenuVisible: false,
});
});
return () => {
AdMobRewarded.removeAllListeners();
};
}, []);
setState is actually not React setState, it's a redux action I have implemented:
const setStateAction = (obj, sceneName) => {
const type = sceneName ? `${sceneName}_SET_STATE` : 'SET_STATE';
return { ...obj, type };
};
Without the rewardedVideoDidRewardUser listener, calling setState does open the Modal and everything is fine.
hintModalVisible is used for Modal isVisible prop, which opens and closes the Modal.
On Android everything works as expected, but there is a strange behavior on iOS. The ad shows for a second and automatically closes, and the Hint Modal doesn't open.
Here is the function that requests and shows the ad. It is present in all screens of the app:
showHint = async () => {
const { setState } = this.props;
try {
setState({
mainMenuVisible: false,
});
await AdMobRewarded.requestAdAsync();
await AdMobRewarded.showAdAsync();
} catch (e) {
setState({
hintModalVisible: true,
mainMenuVisible: false,
});
}
};
It's an open source project, so you can the code here
The problem was with React Native Modal.
setState({
hintModalVisible: true,
adIsLoading: false,
mainMenuVisible: false,
});
This block of code should have closed the main menu modal and open the hint modal. But it seems that on IOS you cannot do this simultaneously. So this is how I handled it.
useEffect(() => {
AdMobRewarded.addEventListener('rewardedVideoDidRewardUser', () => {
setTimeout(() => {
setState({
hintModalVisible: true,
});
}, 1000);
});
return () => {
AdMobRewarded.removeAllListeners();
};
}, []);
And took the closing of main menu modal in the ad requesting function:
const requestHint = useCallback(async () => {
try {
setState({
mainMenuVisible: false,
});
await AdMobRewarded.requestAdAsync();
await AdMobRewarded.showAdAsync();
} catch (e) {
setState({
mainMenuVisible: false,
});
setTimeout(() => {
setState({
hintModalVisible: true,
});
}, 500);
}
}, [setState, hintModalVisible]);
So this is not concerned to the Admob Rewarded. It is more a React Native Modal bug. https://github.com/react-native-community/react-native-modal/issues/192
I try using contents.findInPage.
I have code in index.js:
const { webContents } = require('electron')
webContents.on('found-in-page', (event, result) => {
if (result.finalUpdate) webContents.stopFindInPage('clearSelection')
})
const requestId = webContents.findInPage('api')
console.log(requestId)
And code in component:
searchText(value){
this.query = value;
if (this.query.length > 0) {
ipcRenderer.send('api', this.query);
}
}
I wrote this code on the example of this answer.
But function find not work. I do not understand how I can send the text to be searched and the word to be searched.
How I can use function findInPage ?
sorry my answer to the other question wasn't clear enough (it was 2 years ago! I don't remember it that well but I'll give it a shot)
This is the documentation for webcontents and IPCMain
Here's what I have in my main.development.js (globals for the mainWindow and ipc communication):
mainWindow.on('focus', () => {
globalShortcut.register('CmdorCtrl+F', () => {
mainWindow.webContents.send('find_request', '');
});
});
mainWindow.webContents.on('found-in-page', (event, result) => {
if (result.finalUpdate) {
mainWindow.webContents.stopFindInPage('keepSelection');
}
});
ipcMain.on('search-text', (event, arg) => {
mainWindow.webContents.findInPage(arg);
});
mainWindow.on('blur', () => {
globalShortcut.unregister('CmdorCtrl+F');
});
Then I made an ipc listener for CmdorCtrl+F:
ipcRenderer.on('find_request', () => {
const modalbox = document.getElementById('modalbox');
if (modalbox.style.display === 'block') {
modalbox.style.display = 'none';
} else {
modalbox.style.display = 'block';
}
});
Then I made a modal searchbox:
const searchBox = (
<div
id="modalbox"
style={{ display: 'none', position: 'fixed', zIndex: 1 }}
><input type="text" onChange={Calls.searchPage} />
</div>);
The onchange sends the input text to the ipc listener:
static searchPage(event) {
ipcRenderer.send('search-text', event.target.value);
}
I hope this is enough for you to get it fixed :)