I am developing an extension for personal use, which only automatically repeat some action on a website A. This is basically the flow I want to automate using Chrome extension:
- Trigger a button click event.
- A new popup window is opened (which is opened by website A).
- Fill form into the opened window.
- Click submit button.
Currently, my extension is using Chrome's pageAction for the specific website I want to automate.
manifest.json
{
"manifest_version": 2,
"name": "Automater",
"version": "0.0.1",
"page_action": {
"default_title": "Click here!",
"default_icon": "icon.png"
},
"content_scripts": [
{
"matches": [
"https://www.website.com/*"
],
"js": ["jquery-3.2.1.min.js", "content.js"],
"run_at": "document_end"
}
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"activeTab",
"tabs",
"declarativeContent",
"storage"
]
}
background.js
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var activeTab = tabs[0];
chrome.tabs.sendMessage(
activeTab.id,
{ 'message': 'click_btn' }
);
});
});
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(
undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: {
urlContains: 'www.website.com',
schemes: ['https']
},
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
chrome.windows.onCreated.addListener(function(newWindow) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var activeTab = tabs[0];
chrome.tabs.sendMessage(
activeTab.id,
{ 'message': 'fill_form' }
);
});
});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === 'btn_clicked' ) {
citationsSize = request.citationsSize;
}
}
);
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
switch(request.message) {
case 'click_btn':
$("#btn_id").click();
chrome.runtime.sendMessage({
"message": 'btn_clicked'
});
break;
case 'fill_form':
console.log('start filling');
};
}
);
My problem
I am on the website. After the extension icon is clicked, $("#btn_id").click(); works and it opens a new window as a popup (this popup is opened by the website I'm currently on). I use chrome.windows.onCreated to catch the newly opened window, but, from here, I cannot send a message fill_form to the new window's content script.
How can I execute the script in the newly opened popup window?
1 Answer 1
You can solve this in more than one way, but in my humble opinion you don't really need messages. If you want to execute the content script when you click the page action, then don't add it in the manifest.json, but split it in two different files, one for clicking the button and one for filling and sending the form, then just inject them programmatically when needed using chrome.tabs.executeScript.
The workflow would be the following:
- Page action is clicked.
content_click_btn.jsis loaded in the page and clicks the button.- The popup window is opened.
content_fill_form.jsis injected in the popup window.- The form is filled and submitted.
Your code would become something like this:
background.js:
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: 'content_click_btn.js', runAt: 'document_end'});
});
});
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: {
urlContains: 'www.website.com',
schemes: ['https']
},
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}]);
});
});
NOTE: since January 2021, use chrome.action instead of chrome.pageAction and chrome.scripting.executeScript() instead of chrome.tabs.executeScript().
content_click_btn.js:
function listener(newWindow) {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
if (tabs[0].url.includes('http://www.website.com')
chrome.tabs.executeScript(tabs[0].id, {file: 'content_fill_form.js', runAt: 'document_end'});
});
chrome.windows.onCreated.removeListener(listener);
}
chrome.windows.onCreated.addListener(listener);
document.getElementById('btn_id').click();
content_fill_form.js:
console.log('Filling the form...');
// Do something to fill and send the form.
Also, you don't actually need it, but if you want to use jQuery you can just leave it in the "content_scripts" field in your manifest.
3 Comments
content_script is not executed after new popup window created using windows.onCreated. As @wOxxOm comment, I need to put it within tabs.onUpdated. Your approach fits with my "simplified" flow in the question. However, after submit I also want to listen/check/catch the response from the last submitted form. I will try to re-organize my code with your approach, it has a better design for code management.webRequest API is really helpful for my flow. Thank you again.
chrome.tabs.onUpdatedperfectly solve my problem.