0

What I want to do is to run go() function in image.js file. I've googled around and I understand that is not possible to run inline scripts.

What is the best method to call the JavaScript I want? Events? Messages? Requests? Any other way?

Here is my code so far:

background.js

chrome.browserAction.onClicked.addListener(function(tab) {

var viewTabUrl = chrome.extension.getURL('image.html');

var newURL = "image.html";
chrome.tabs.create({
    url : newURL
});

var tabs = chrome.tabs.query({}, function(tabs) {

    for (var i = 0; i < tabs.length; i++) {
        var tab = tabs[i];
        if (tab.url == viewTabUrl) {
            //here i want to call go() function from image.js
            
        }
    }
});
});

image.html

<html>
  <body>
  <script src="js/image.js"></script>
  </body>
</html>

image.js

function go(){
  alert('working!');
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

2 Answers2

1

There are various ways to achieve this. Based on what exactly you are trying to achieve (which is not clear by your question), one way might be better than the other.

An easy way, would be to inject a content script and communicate with it through Message Passing, but it is not possible to inject content scripts into a page with the chrome-extension:// scheme (despite what the docs say - there is an open issue for correcting the docs).

So, here is one possibility: Use window.postMessage


E.g.:

In background.js:

var viewTabURL = chrome.extension.getURL("image.html");
var win = window.open(viewTabURL);   // <-- you need to open the tab like this
                                     //     in order to be able to use `postMessage()`

function requestToInvokeGo() {
    win.postMessage("Go", viewTabURL);
}

image.js:

window.addEventListener("message", function(evt) {
    if (location.href.indexOf(evt.origin) !== -1) {
        /* OK, I know this guy */
        if (evt.data === "Go") {
            /* Master says: "Go" */
            alert("Went !");
        }
    }
});
Community
  • 1
  • 1
gkalpak
  • 47,844
  • 8
  • 105
  • 118
  • I tried your code and it's not working for me. I'm probably doing something wrong. When are you calling the function "requestToInvokeGo()" ? – user2882482 Nov 21 '13 at 14:49
  • I did not include a call to `requestToInvokeGo()`, thinking you can invoke it whenever you want (and as many times). When are you trying to invoke it and it isn't working ? Do you get any errors in the console of either the background page or `image.html` tab ? – gkalpak Nov 21 '13 at 14:55
  • No errors. As far as i understood, listener is not reacting (i put a console.log at the beginning at it's not printing). – user2882482 Nov 21 '13 at 15:07
  • Do you invoke `requestToInvokeGo()` ? How/When ? – gkalpak Nov 21 '13 at 15:22
  • Inside "background.js" after the definition – user2882482 Nov 21 '13 at 15:41
  • I try it and it works fine. Could you post or somehow share your code ? – gkalpak Nov 21 '13 at 15:41
  • Could it be because of the manifest ? I have this ` "content_scripts": [ { "matches": ["*://*/*"], "js": ["js/image.js"] } ], "permissions": [ "tabs", "http://*/*", "https://*/*", "file://*/*" ]` – user2882482 Nov 21 '13 at 15:48
  • I now see you changed your original comment about invoking it from the browserAction. If you invoke it immediatelly after you open the window, it might not work since the posted message could arrive before the JS script is loaded and listens for messages. If you want it to run as soon as the page is loaded, add a call directly in `image.js` (e.g. `window.addEventListener("load", go);`). After that you can call it as many times as you want from the background script. As I mentioned in my answer, there are several ways to achive this, even through message-passing, so if you describe exactly what – gkalpak Nov 21 '13 at 15:54
  • you are trying to achieve, we might be able to provide a better/cleaner/sorter solution. – gkalpak Nov 21 '13 at 15:54
  • Well, i'm starting to confuse myself... What i was trying to achieve was pretty much this: my `background.js` will have functions calls like `example()` and `example_2()` and every time this functions are called i want to call the function that is in another page `helper.js (helper.html)` but i was having problems because of the restriction of running inline scripts – user2882482 Nov 21 '13 at 16:07
  • Is there going to be only one `helper.html` page ? If not how do you determine which page's function will be executed ? – gkalpak Nov 21 '13 at 16:11
  • Yes, i will know in which file is the function to call – user2882482 Nov 21 '13 at 16:15
  • My question is: Is there going to be only one `helper.html` open at a time ? – gkalpak Nov 21 '13 at 16:24
  • Yes. Even if more pages are opened i guess i can loop through the pages and force the function to execute from that page right ? – user2882482 Nov 21 '13 at 16:26
  • Have you tried doing it like I propose above, but not calling it right away. After the page has loaded, open the background page's console window and type `requestToInvokeGo()`. Does it work for you ? – gkalpak Nov 21 '13 at 16:38
  • That way it worked ! The problem is probably what you pointed out previously about evoking it to earlier and not to let time enough to load. – user2882482 Nov 21 '13 at 16:49
  • i can't figure it why it's not working if i call it in background.js – user2882482 Nov 21 '13 at 17:19
  • What can't you figure out ? It is what I explained earlier (it's a timing issue). Besides, if you use a non-persistent background page (which is advisable), it would be invoked every time the background page got loaded which is not what you want (a non-persistent bg page can get loaded very often - not just on browser start-up). If you want it to get invoked as soon as the page loads, put a call (`go();`) in `image.js` itself. For all other (later) invokations, the code will work just fine. – gkalpak Nov 21 '13 at 18:05
0

In general, the easiest method to communicate between the background page and extension views is via direct access to the respective window objects. That way you can invoke functions or access defined properties in the other page.

Obtaining the window object of the background page from another extension page is straightforward: use chrome.extension.getBackgroundPage(), or chrome.runtime.getBackgroundPage(callback) if it's an event page.

To obtain the window object of an extension page from the background page you have at least three options:

  1. Loop through the results of chrome.extension.getViews({type:'tab'}) to find the page you want.
  2. Open the page in the first place using window.open, which directly returns the window object.
  3. Make code in the extension page call a function in the background page to register itself, passing its window object as a parameter. See for instance this answer.

Once you have a reference to the window object of your page, you can call its functions directly: win.go()

As a side note, in your case you are opening an extension view, and then immediately want to invoke a function in it without passing any information from the background page. The easiest way to achieve that would be to simply make the view run the function when it loads. You just need to add the following line to the end of your image.js script:

go();

Note also that the code in your example will probably fail to find your tab, because chrome.tabs.create is asynchronous and will return before your tab is created.

Community
  • 1
  • 1
rsanchez
  • 14,467
  • 1
  • 35
  • 46
  • Adding that line make it work but it's running when i want. I want to have control of when it's running. – user2882482 Nov 21 '13 at 14:51
  • I'm stuck on step three. I've added `chrome.extension.getBackgroundPage().helpWindowLoaded(window);` on `image.js` and `function helpWindowLoaded(helpWindow) { helpWindow.help(id); }` on `background.js` but it says that id is not defined. I defined an id and it says that "helpWindow" has not a method called "help". – user2882482 Nov 21 '13 at 16:28
  • @user2882482 of course, that was a function specific to that question. In your case it would be `helpWindow.go()`. Also: 1, 2, and 3 are not steps, but different alternatives. – rsanchez Nov 21 '13 at 16:36
  • 1
    1. `chrome.tabs.create` won't return before the tab is created (probably before it's done loading, but not before the tab is created). 2. Do not promote the use of the obsolete **chrome.extension.getBackgroundPage()**. Use **chrome.runtime.getBackgroundPage(callback)** instead. (The former won't even properly load an event page before returning.) – gkalpak Nov 21 '13 at 18:09