So in a chrome extension.
when the user clicks a button
send a message to background
open a new popup window
in the new window, click on the specific element
I can get most of the way but fail to be able to focus in on the necessary document for the js to get the element ID on.
content.js
user_clicked_btn.addEventListener('click', () => {
chrome.storage.sync.get(['xyz'], (result) => {
if (result.xyz['u'].includes('123') && result.xyz['da'] !== 'cool') {
chrome.runtime.sendMessage(
{
s: 'quick',
}
);
}
});
background.js
chrome.runtime.onMessage.addListener((request) => {
if (request.s === 'quick') {
chrome.windows.create({
url: './options.html', type: "popup", focused: true
},
() => {
let queryOptions = { active: true, currentWindow: true };
chrome.tabs.query(queryOptions, function (tabs) {
tabs[0].document.getElementById("element_of_interest").click()
});
}
);
}
});
the issue could be summarized as, how do I get the "document" of a different tab? (assuming I own the 'different tab')
The solution for my problem was to add message passing the whole way to the element of interest and have it click itself.
The result looks like this and behaves as desired.
content.js
user_clicked_btn.addEventListener('click', () => {
chrome.storage.sync.get(['xyz'], (result) => {
if (result.xyz['u'].includes('123') && result.xyz['da'] !== 'cool') {
chrome.runtime.sendMessage(
{
s: 'quick',
}
);
}
});
background.js
chrome.runtime.onMessage.addListener((request) => {
if (request.s === 'quick') {
chrome.windows.create({
url: './options.html', type: "popup", focused: true
}, () => {
setTimeout(() => {
console.log("send message to options page")
chrome.runtime.sendMessage(
{
s: 'quick_click',
}
);
}, 1000);
});
}
});
in the options.html file, the desired element is a react element, so I was able to add a listener in the componentDidMount function
options/index.js
componentDidMount() {
chrome.runtime.onMessage.addListener((request) => {
if (request.s === 'quick_click') {
this.handleClick()
}
});
}
Related
I've a state named modal in my React App. The initial value is an object that says {show: false, photo: null}.
I've two buttons in the page. One is calling the close function and another is calling the open function. open is setting the state to {show: true, photo: true} and close is just logging modal
I also wrote some code to call the close function when the Esc button is clicked.
Here's my code:
function App() {
const [modal, setModal] = useState({ show: false, photo: null });
// open func
function open() {
setModal({ show: true, photo: true });
}
// close func
function close() {
console.log(modal);
}
// function for esc key press
function escFunc(event) {
if (event.key === `Escape`) {
close();
}
}
useEffect(() => {
document.addEventListener(`keydown`, escFunc, true);
return () => {
document.removeEventListener(`keydown`, escFunc, true);
};
}, []);
return (
<>
<button onClick={open}>open</button>
<br />
<button onClick={close}>close</button>
</>
);
}
so now when I click the open button and then click the close button, it's logging {show: true, photo: true} (as expected). but the problem comes in if I press Esc now. It should log {show: true, photo: true} (as the state is already updated by the open function), but it's logging {show: false, photo: null} as if the state hasn't changed yet
Why is it happening?
Whenever a component rerenders, the entire function is reran.
In your useEffect, which is only called on the first render, you call document.addEventListener with the callback function escFunc. This escFunc has a closure that stores the value of modal, which is a reference to the original object state { show: false, photo: null }.
In your open function, you set the state to { show: true, photo: true } using the object literal syntax, which creates a whole new object with a new reference location.
The event listener is still tracking the original object.
To be able to get the new state reference, you need to remove the old event listener and then add a new event listener.
There are multiple ways to do this.
useEffect(() => {
document.addEventListener(`keydown`, escFunc, true);
return () => {
document.removeEventListener(`keydown`, escFunc, true);
};
}, [modal]); // add modal to dep array
useEffect(() => {
document.addEventListener(`keydown`, escFunc, true);
return () => {
document.removeEventListener(`keydown`, escFunc, true);
};
}, [escFunc]); // add escFunc to dep array, but this would run every render
Stylistically, this is the best option because it properly shows dependencies and doesn't have extra rerenders, but the calls to useCallback might make it slower
const close = useCallback(function() {
console.log(modal);
}, [modal]); // depends on modal
const escFunc = useCallback(function(event) {
if (event.key === `Escape`) {
close();
}
}, [close]); // depends on close
useEffect(() => {
document.addEventListener(`keydown`, escFunc, true);
return () => {
document.removeEventListener(`keydown`, escFunc, true);
};
}, [escFunc]); // add escFunc to dep array
In fact, you don't even need to have escFunc outside of useEffect if you don't use it elsewhere
const close = useCallback(function() {
console.log(modal);
}, [modal]); // depends on modal
const escFunc = useCallback(function(event) {
if (event.key === `Escape`) {
close();
}
}, [close]); // depends on close
useEffect(() => {
function escFunc(event) {
if (event.key === `Escape`) {
close();
}
}
document.addEventListener(`keydown`, escFunc, true);
return () => {
document.removeEventListener(`keydown`, escFunc, true);
};
}, [close]); // add escFunc to dep array
I am building an extension in which content script is injected on context menu click. This functionality is working. Now the problem I am facing is that, whenever I open a new tab, the
chrome.runtime.onMessage.addListener
will get triggered without context menu click. How can I invoke the onMessage.addListener only on context menu click.
background.js
on_message = async(message, sender, sendResponse) => {
console.log("bg.on_message");
sendResponse("from bg");
chrome.storage.local.get("list_url", function (data) {
if (typeof data.list_url != "undefined") {
urls = data.list_url
}
});
chrome.storage.local.get("list_ip", function (data) {
if (typeof data.list_ip != "undefined") {
ips = data.list_ip
}
});
chrome.storage.local.get("list_hash", function (data) {
if (typeof data.list_hash != "undefined") {
hashes = data.list_hash;
}
});
if (hashes){
hash_report = await createHashReport(hashes)
hash_table = await createHashTable(hash_report)
chrome.storage.local.set({
"scanHash": true,
"hash_table": hash_table
}, () => {});
}
if (ips){
ip_report = await createIpReport(ips)
ip_table = await createIpTable(ip_report)
chrome.storage.local.set({
"scanIp": true,
"ip_table": ip_table
}, () => {});
}
if (urls){
url_report = await createUrlReport(urls)
url_table = await createUrlTable(url_report)
chrome.storage.local.set({
"scanUrl": true,
"url_table": url_table
}, () => {});
}
if ( hashes.length>0 || urls.length>0 || ips.length>0 ){
chrome.windows.create({url: "output.html", type: "popup", height:1000, width:1000});
}
}
chrome.runtime.onMessage.addListener(on_message);
genericOnClick = async () => {
// Inject the payload.js script into the current tab after the backdround has loaded
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
files: ["payload.js"]
},() => chrome.runtime.lastError);
});
}
payload.js
function extract() {
htmlInnerText = document.documentElement.innerText;
url_exp = /[-a-zA-Z0-9#:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9#:%_\+.~#?&//=]*)?/gi;
regex = new RegExp(url_exp)
list_url = htmlInnerText.match(url_exp)
ip_exp = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/;
list_ip = htmlInnerText.match(ip_exp)
hash_exp = /\b[A-Fa-f0-9]{32}\b|\b[A-Fa-f0-9]{40}\b|\b[A-Fa-f0-9]{64}\b/g
list_hash = htmlInnerText.match(hash_exp)
chrome.storage.local.set({ list_url: removeEmails(removeDuplicates(list_url)), list_ip: removeDuplicates(list_ip), list_hash: removeDuplicates(list_hash) });
}
chrome.runtime.sendMessage( extract())
Remove the following definition from manifest.json.
"content_scripts": [
{
"js": [
"payload.js"
],
"matches": [
"<all_urls>"
]
}
]
I have a problem, I can't remove the event listener in the condition inside the callback function.
I have the impression that the syntax is correct. But the event is still active.
Does anyone know how to remove the event touchstart?
mutation.target.removeEventListener("touchstart",(e) => { handleClickButton(e) }, true);
const headerSearchBox = document.querySelector(".search-box");
function handleClickButton(event) {
event.preventDefault();
alert("You Clicked on the button")
}
const mutationCallback = function (mutationList) {
mutationList.forEach((mutation) => {
let isSearchOpen = mutation.target.classList.contains("search-container");
// If Search Bar is Open : Do This...
if (mutation.type === "attributes" && isSearchOpen && mutation.oldValue.includes("open")) {
console.log("Search Bar is Open");
mutation.target.addEventListener("touchstart",(e) => { handleClickButton(e) }, true);
} else {
console.log("Search Bar is Close");
mutation.target.removeEventListener("touchstart",(e) => { handleClickButton(e) }, true);
}
});
};
const observer = new MutationObserver(mutationCallback);
observer.observe(headerSearchBox, {
attributes: true,
attributeOldValue: true,
attributeFilter: ["class"],
});
Thanks for your support
I am using the onclick function with window.open popup, the popup comes to front with the same button, but after closing it is not opening again
<Button hideLabel aria-label={zxxxx "}
className = {styles.button}
icon = "plus"
color = "danger"
size = "lg"
circle
onClick = {
() => {
if (!this.state.isOpened) {
this.setState({
isOpened: true
})
var mywin = window.open("https://app.mural.co", "MsgWindow", "width=1366,height=768")
mywin.addEventListener("beforeunload", function(e) {
this.setState({
isOpened: true
})
}, false)
this.setState({
windows: mywin
}
this.setState(mywin)
}
else {
const window = this.state.windows;
if (window) {
window.focus();
}
}
}
}/>
There is something wrong in your code. Please refer to the commented line.
if (!this.state.isOpened) {
this.setState({
isOpened: true
})
var mywin = window.open("https://app.mural.co", "MsgWindow", "width=1366,height=768")
mywin.addEventListener("beforeunload", function(e) {
this.setState({
isOpened: true
})
}, false)
this.setState({ // there is no closing parenthesis for this
windows: mywin
}
this.setState(mywin)
}
else {
const window = this.state.windows;
if (window) {
window.focus();
}
}
}
Moreover aria-label={zxxxx "} also is missing something. I would highly recommend a code editor that points out these errors for you.
I want to create an app that has an alert for check connection with two button one is exit for the exit app and two is try again for check connection again,
I searched about it and I tried about it, but I can n't solved this problem please help me.
import { Injectable } from '#angular/core';
import { Network } from '#ionic-native/network/ngx';
import { AlertController } from '#ionic/angular';
#Injectable({
providedIn: 'root'
})
export class CheckInternetService {
public base: string; // this will be set in the constructor based on if we're in dev or prod
timer: any;
constructor(private network: Network, private alertCtrl: AlertController) {}
async presentAlert() {
const alert = await this.alertCtrl.create({
header: 'خطا',
backdropDismiss: false,
subHeader: 'قطعی انترنت',
message: 'لطفا انترنت خودرا چک کنید',
buttons: [{
text: 'خروج',
handler: () => {
navigator['app'].exitApp();
}
},
{
text: 'تلاش مجدد',
handler: () => {
this.doSomething().then(res => {
this.checkConnection();
});
}
}
],
});
await alert.present();
}
doSomething() {
return new Promise((resolve, reject) => {
// pretend a long-running task
this.timer = setTimeout(() => { resolve(true); }, 3000);
});
}
checkConnection(): boolean {
if (document.URL.includes('https://') || document.URL.includes('http://')) {
this.base = 'http://127.0.0.1:3001/';
} else {
this.base = 'https://url.to_actual_URL.com/';
}
const type = this.network.type;
let online;
if (type === 'unknown' || type === 'none' || type === undefined) {
online = false;
this.presentAlert();
} else {
online = true;
clearTimeout(this.timer);
}
this.network.onDisconnect().subscribe( () => {
online = false;
this.presentAlert();
});
this.network.onConnect().subscribe( () => {
online = true;
clearTimeout(this.timer);
});
return online;
}
}
This is my code that I was trying on, I work on this code but I do n't any answer, please help me.
You can make try again button with out any timer, you can use this code for your problem:
async presentAlert() {
this.alertCtrl.dismiss();
const alert = await this.alertCtrl.create({
header: 'خطا',
backdropDismiss: false,
subHeader: 'قطعی انترنت',
message: 'لطفا انترنت خودرا چک کنید',
buttons: [{
text: 'خروج',
handler: () => {
navigator['app'].exitApp();
}
},
{
text: 'تلاش مجدد',
// role: 'cancel',
handler: () => {
// this.doSomething().then(res => {
// this.checkConnection();
// });
const type = this.network.type;
if (type === 'unknown' || type === 'none' || type === undefined) {
this.presentAlert();
}
},
}
],
});
await alert.present();
}
I don't think you can have a alert box with two buttons because Alert box gives only one button "OK" to select and proceed. . You can show a modal instead of a alert box with as much button as you want.