Howto send a message from content-script to inactive popup, chrome extension - google-chrome-extension

I want to log text on any webpage (using content-script to handle selection) into a database that is popup's resource in order to collect text in one place.
what i am trying
I create a database in popup page and try to manage it from content-script though popup is not active (not opened) by using chrome messaging but cannot make the popup receives any message from content-script.
I'm not sure about using messaging to solve this problem.
Is there any better solution?

A content script cannot send a message to an invisible popup, because the popup's context is inactive (closed) when it's hidden.
There are several solutions to your problem.
Option 1: No message passing, use storage events
If your "database" is in fact a simple key-value store, switch to the chrome.storage API. This API is available to the Content script and the popup, and comes with an event to notify you of value changes.
Example:
// Get notified of changes (in the popup?)
chrome.storage.onChanged.addListener(function(changes, areaName) {
// Do whatever you want with the changes.
});
// Initialization of the popup (print initial information?)
chrome.storage.local.get({keyName: 'defaultValue'}, function(items) {
// Do something with items.keyName
});
// Content script, storage (remember document title?)
chrome.storage.local.set({keyName: document.title});
Option 2: Pass messages to the background/event page
The popup and the background / event page share the same process. Any database tied to the popup is also available to the background page, and vice versa. A high-level overview of this method:
Content script sends a message to the background page.
The background page stores the value in the database
If the popup is open, update the popup's view.
If the popup is opened (so it was closed before), it should read the database (either directly, or by reading data from the background page using chrome.runtime.getBackgroundPage) and handle the results.
I've provided the code corresponding to this flow in this answer.

Related

Chrome extension: How to do not lose state of my extension when user changes/reloads the page

I'm currently developing an extension that comes in different parts:
- background script (Chrome background.js
- content script (Chrome content-script.js)
- popup script (popup.js and loaded from the iFrame)
- iframe.html (iframe to be loaded when user activate the extension)
It works great except that I lose all the settings/context (used in the popup script to display info in the iframe) when the user change of page or reload the page in the tab.
Technically I want to isolate the extension per tab (each tab can have its own config) but when a user navigate in a same tab the context should be kept.
Question is: what is the best way to achieve that?
I'm thinking about persisting all the context in the content script and reload it when the event chrome.tabs.onUpdated is fired. Is it the right approach?
I recommend you to read about chrome.storage. You can store data there, both background and content script have access to it.
And probably you will need chrome.runtime.sendMessage and chrome.runtime.onMessage to have conversation between background and content. Each time content script runs in a tab it can request background whether this tab have some existing data or not.

Chrome extension to capture formdata and use this data to form fill in another tab

I am trying to build a simple chrome extension so that when a form on a webpage in a specific website is populated and the user presses Submit then the data in the form is captured and then some of that data is injected into another form running on a different website.
I have no access to edit the code for either of the forms so a chrome extension seems to be the best way to do this from what I have read.
I would like to know if this is possible and how to go about it
It is possible using Content Scripts, a Background Page, and/or Chrome.storage
You will need Content Scripts on both websites that have the forms. Use the Manifest File correctly to set up which websites to attach which Content Scripts to.
The first Content Script (the one reading the form being filled and submitted) will have to take the values of each form input, triggered by the submit button.
Then you will need to use Message Passing to send a message (containing all the form data) from that Content Script to your Background Page. The data can be held temporarily or saved into chrome.storage by the Background Page.
Then the second form's Content Script also uses Message Passing to request the data from Background Page, which is delivered from temporary holding or retrieved from chrome.storage then sent.
And finally the second Content Script modifies its website's form to fill in the values.

Is it ok to repeatedly add event listener in the event pages for chrome extension?

I am learning the Event Pages for Chrome extension and according to the documentation, the scripts will only be loaded when needed. Then I find that the Google Mail Checker's event page script will add the event listener:
// Some declarations
chrome.browserAction.onClicked.addListener(goToInbox);
// ...
And I write an event script:
chrome.tabs.create({url: 'https://www.google.com'});
function onClickListener() {
chrome.tabs.create({url: 'https://www.bing.com'});
}
chrome.browserAction.onClicked.addListener(onClickListener);
After I reloaded my extension, a new tab of google.com is opened as expected. Seconds later the process of my extension is gone in Chrome's task manager, and I clicked the extension icon. Then, both google.com and bing.com are opened! So I learn that this entire script will be loaded again.
Now look back to the script of Google Mail Checker. The listener will be added repeatedly once the script is loaded, so my question is: is it ok to add listener repeatedly? If the listener's behavior will change from A to B when the script is loaded, which one will be fired on the second load, A or B?
In fact your question is logically impossible, since the documentation has stated that the event listener will only exist in the context of the event page, that means it will be automatically removed once the event page is unloaded. So to some degree, it's ok to add listener repeatedly, although in fact you are adding it only once.
Because the listeners themselves only exist in the context of the event page, you must use addListener each time the event page loads
And Chrome also states that in the first line of best practices when using event pages
Register to receive any events your extension is interested in each time the event page is loaded. The event page will be loaded once for each new version of your extension. After that it will only be loaded to deliver events you have registered for. This generally means that your event listeners should be added at the top level scope of the event page, otherwise they may not be available when the event page reloads.

What can you do in background scripts that you can't do in other js files?

*By other js files, I mean the files you include in popup.html.
The following code works, so why should I use a background script?
Content script
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
//Some code
}
);
Script included in popup.html
chrome.tabs.query({active:true,windowId: chrome.windows.WINDOW_ID_CURRENT},
function(tab) {
chrome.tabs.sendMessage(tab[0].id, {method: "someMethod"},
function(response){
//Some code
});
});
This
Background pages live as long as the Chrome browser is active (and even longer if the "background" permission is set). Popup pages are only active when the badge's popup is open. The popup can only be opened by the user.
The background page's document is never visible, whilst the popup page becomes visible on click of the badge's button.
Besides that, there's no difference between background pages and popup pages. They run in the same extension's process, and have access to the same set of APIs.
If your extension only needs to be active while the popup is active, you don't need a background page. To save the state of the popup, just use the synchronous localStorage or the asynchronous chrome.storage API. When the variables you use are too complex to be stored using either API, a background page may be useful.
One example where the use of a background page is beneficial:
Imagine an extension that downloads a huge text file from a server. The creation of the resource is very resource-intensive for the server. Technically, everything can be done from within the popup. However, offloading the task to the background page allows the user to do other tasks while the file is downloading (if you use a popup only, the download will stop when the user closes the popup).
Though you didn't ask, I'd like to make you aware of event pages. They are similar to background pages, with one difference: Event pages are automatically closed when the extension is idle. In other words, event pages are only active when needed! By doing this, your extension will profit from the advantages of background pages without needlessly wasting the user's memory.
My last example is also a perfect example of when an event page has to be used. Besides doing the http request on behalf of the popup, the background page does nothing. If you use an event page instead of a background page, you get the best of both worlds: the popup page can be closed without interrupting the download, and the extension will not waste memory.
Documentation
Learn more about Background pages and Event pages
"Popup" in this answer refers to the optional panel of the chrome.browserAction or chrome.pageAction API, set by declaring the "default_popup" key in the manifest file, or programatically using the setPopup method.

Calling chrome.browserAction.setIcon from content script the way it is done in background script

I am making an extension for chrome. It fetches data from webpages and emails it via local email client. I have a toolbar button which user has to click to invoke the script.
My script works for a few selected urls. I want my toolbar button to change icon based on whether the url is among our list or not. For example for site1 it should be redicon.png and for site2 it should be blueicon.png. I can change button icon using chrome.browserAction.setIcon. But the problem is that this API does not work in content script. It works fine in the background.js file but not in content.js. Kindly tell me how to achieve this.
I know using pageAction instead would do the trick but my client requirement is that the toolbar icon should change rather than appear and disappear.
What you need to read about is message passing. You are right, content scripts have limited chrome API. However, you can contact background page from content script and tell it to execute anything from chrome API for you. First, you need to create a listener on a background page that will be waiting for messages and then send a message from a content script.

Resources