Open and pass data to a popup (new tab) from content script - google-chrome-extension

I'm writing a chrome extension and have a question.
My extension has some .html page in it, let it be 'popup.html'. I inject a content script into some page and this script opens a 'popup.html' in a new tab with something like 'var p = window.open(chrome.extension.getURL('/popup.html'), "popup")', which works perfectly. Next, I need to pass some data to this window and I can't figure how to do it in a simple way.
For some reason I can't call child window's function from a content script with
var p = window.open(chrome.extension.getURL('/popup.html'), "popup");
p.foo(data);
In the console I see Uncaught TypeError: Cannot call method 'foo' of undefined message.
I can't pass data in a query string, because the data is simply too big.
Is there an elegant and simple way to pass data to such kind of window? I thought about messaging, but how do I effectively get tab ID of a newly opened window w/out using a background page?
Thanks a lot in advance.
UPD:
I tried to inverse the logic and get a data from parent window with 'window.opener.foo()' but in a newly opened tab window.opener returns null.

Ok, I found two solutions to my problem.
1) Add a background page, which opens a popup with chrome.tabs.create(). Then send a message from a content script to a background page, which re-sends it to a corresponding tab via chrome.tabs.sendMessage(). It looks a little ugly, but works.
2) A better one, w/out background page. Extension (popup) page creates a listener for long-lived connection. Then content script sends a message to this connection. A problem here is that a listener is not created right after the page is opened, so there should be a mechanism for a content script to wait until popup is loaded. It can be a simple setTimeout or a notification from popup via same long-lived connection.
If anyone has a better solution I'd gladly check it out as well.

Related

Wait for chrome.tabs.update tab to finish loading

I'm trying to work on a chrome extension and am trying to clean up some of my code by relying on the sendMessage. However the callback function activates before the page has finished loading so in the case of a new tab, nobody receives and in the case of an existing tab the page that is being moved from is getting the message (but that isn't what I want). I've looked for other people asking about that problem with new tabs and there wasn't a clear answer, the best suggestion I've seen is to create a global variable and create a listener for tab loads and compare it against this global variable.
So the question is, is there a way to wait in the callback function until the page has loaded, or do I create an array of JS objects that contain the tab I'm waiting on and the information I want to send to that tab.
For reference here is the relevant code in the background javascript file.
chrome.tabs.sendMessage(tab.id, {info: "info"}, function(response)
{
//This line isn't used when I am navigating without changing tabs
chrome.tabs.create({url: response.info.linkUrl}, function(tab1)
{
chrome.tabs.update(tab1.id, {url: response.info.linkUrl}, function(tab2)
{
chrome.tabs.sendMessage(tab2.id, {info: "More Info"});
});
});
});
Otherwise I am able to confirm that all of my tab side code works, once my sendMessage was delayed enough for me to see that with my own eyes. My code is able to consistently make it past validation on the page being navigated away from, confirmed by checking document.url.
You can try injecting a second content script instead of a message.
It will execute in the same context as your other script.
Something along the lines of
chrome.tabs.executeScript(tab2.id,
{code: 'showInfo("More Info);', runAt: 'document_idle'}
);
where showInfo does the same as your message handler.
It's a bit of a hack and I'm not 100% sure the load order will be correct.
Other possible solutions are more complex.
For example, you can make the content script report back that it is ready and have a handler for that, for instance you can register a listener for onMessage in the background that waits for a message from that specific tab.id, sends "More Info" and then deregisters or disables itself.
Or, you could potentially switch to programmatic injection of your content script, which would let you control load order.

How To Make Page To Interact With Background Page?

My Chrome extension has a background page that execute script on current tab.
The script change elements on current tab by adding code to existing elements to call function 'myFunction' defined at background page when 'onClick' events occur.
The problem is that exception is thrown that 'myFunction' is not defined on current tab.
what is the best way to enable this interaction? to enable current page to go to function defined on background page?
Thanks in advance!
The background page is executed in an independent context, and thus its functions can't be directly executed in the currently opened tab.
What you need is a content script executed on all the tabs, that then communicates with the background page, using the message passing mechanism.
Without more information, it's difficult to help you more.
As mentioned in the first answer, "Without more information, it's difficult to help you more.", but for your second question it sounds like what you need is a reference to the function defined in your background page. This can be achieved with the getBackgroundPage function. The code looks like this;
var bgPage = chrome.extension.getBackgroundPage();
bgPage.myFunction();

Can Popup page use DOM elements created in Background Page

Actually, I want to store some data in background page and the popup page just show that part of data say Data as a div element created in background page document.createElement("div"). Here, the background page will register some listeners to the tab update and change the Data elements accordingly. What the popup will do is to get that Data and appendit use the document.appendChild(Data).
(The purpose I intend is this will cause the popup changes immediately while the tab updage is triggered.)
However, the elements are shown as usual, what I am facing very headache is I have registered the onclick for the div object in backgroundpage as onclick="chrome.extension.getBackgroundPage().somefunc()". However, the first time, all the click will triger the right behavior but after the popup loses foucs and get focus again, all the click won't work.
I try to put something like change the onclick="somefunc()" and leave the func within the script of popup page. And there I want to log whether it is called by console.log("clicked"). Here, something unbelievable happens, the function is succefully trigerred BUT the console is null here, I cannot even call chrome.extension.getBackgroundPage() as well.
Here are a list of questions, maybe very hard to express for me...
1. Whether I can reuse the DOM element from the background page to the popup page directly by appendChild(chrome.extension.getBackgroundPage().getElementById()?
2.Will the onclick event registered in the background page still work in the popup pages?
3. What's the problem with the problem I am encountering? I have tried many ways to find out the reason but all in vain at last...
Best Regards,
If you need any more information, please let me know.
(PS: I am wonderning if it is called something like the event propogation, however, I am not an expert in this two pages communicating...)

Hidden tabs in google chrome extensions

I've a chrome extension that sends a message from the content script to the background page and logs the tab_id of the content script.
I noticed that on google.com|de|at two messages are logged thus two content scripts are created: one for the actual web page shown in the tab (e.g. https://www.google.com/search?q=python+standard+library ) and another content script for the first item in the google result list ( in the above example http://docs.python.org/library/ )
Even stranger - the tab_id of the second content script (the hidden one) is not valid. I.e. chrome.pageAction.hide(tab_id) causes the following error to appear:
Error during pageAction.hide: No tab with id: 71
Is there a way to figure out if a content script belongs to a "hidden" tab?
thanks,
Peter
First of all, you can use onCreated and/or onUpdated to keep track of tabs and url mappings without the need for a content script.
However, if there's more to your content script than just informing the background page of the tab id, it may mean more checking.
If your content script is run on all_frames, then you will be getting messages from the content script in the top window and all internal frames. Still, when I test a sample implementation, I get the same IDs for all of them. Also, none of them appear to be from entries in the search result list.
If you are running the script in all tabs, you can ensure that only the top window sends the message by wrapping your sendRequest call with an if (window.top === window).
Could it be possible that you have another extension running that previews google results somehow? That may have this effect....

What is window message for a loaded website in Internet Explorer?

I am currently have this message handler line:
MESSAGE_HANDLER(`WM_SETREDRAW`, onSetRedraw)
I would like to know, is there any window message (eg: WM_???) that is connected/related to 'when a website has finish loading inside IE' ?
So I can use it to replace the above WM_SETREDRAW. I want to do something like, when the IE finish loaded a website, it call onSetRedraw.
If no one answers, go Gogoling for an application "spy" tool, which will tell you which messages your program receives. Make a one line app which one launches the browser and spy on that.
Alternatively, what API are you using to launch the browser? Look at it's return value.
Btw, I strongly suspect that you will only get a message when the browser is launched, not every time it loads a new page (or even the first page).
You may not be able to do what you want very easily. A possibility might be to search for the window by title bar, get it's handle, walk its control list until you get to the status bar and check its text in a loop until it is done.
A further possibility, if this is only for yourself, woudl be to get an open source browser which uses the MSIE rendering engine and make a one line change at "the right place in the code" to send a message to your app every time a new page is loaded.

Resources