1

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:

  1. Trigger a button click event.
  2. A new popup window is opened (which is opened by website A).
  3. Fill form into the opened window.
  4. 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?

Marco Bonelli
71k21 gold badges129 silver badges153 bronze badges
asked Oct 3, 2017 at 20:19
2
  • 1
    The content script gets injected after you send the message. Check it by opening devtools in the new window, Sources panel, Content scripts subpanel. You can simply add a timeout before sendMessage or use chrome.tabs.onUpdated inside onCreated. Commented Oct 3, 2017 at 20:24
  • @wOxxOm: thanks to your comment, I can sure that the content script is injected. And using chrome.tabs.onUpdated perfectly solve my problem. Commented Oct 5, 2017 at 7:26

1 Answer 1

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:

  1. Page action is clicked.
  2. content_click_btn.js is loaded in the page and clicks the button.
  3. The popup window is opened.
  4. content_fill_form.js is injected in the popup window.
  5. 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.

answered Oct 4, 2017 at 14:08
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your solution, my problem is that the 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.
@FiriceNguyen you're welcome, remember that you can use the webRequest API to easily intercept requests/reponses like this one.
yes the webRequest API is really helpful for my flow. Thank you again.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.