7

Upon receiving a message from a content script I want to create a new tab and fill the page it opens dynamically (for now I'm just trying to turn the newly created page red).

eventPage.js:

// ... code that injects another content script, works fine

// Problem code...
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) 
  {
    chrome.tabs.create({url: chrome.extension.getURL("blankpage.html")}, 
                       turnTabRed);      
  });

function turnTabRed(tab)
{
  chrome.tabs.executeScript(
    tab.id,
    {code: 'document.body.style.backgroundColor="red"'}
  );
}

This successfully creates a new tab and loads blankpage.html (which is just an HTML page with some text) fine, but fails to paint the background colour red. After inserting console.log() statements in various places and fooling around in the debugger, I have ascertained that turnTabRed is being called, tab.id is indeed the ID of the newly created tab and if I call document.body.style.backgroundColor="red" from the console, the background of the new tab turns red. I noticed that if I added

(*)

chrome.tabs.query(
    {}, function (tabArr) { for (var i = 0; tabArr[i]; i++)    
                              console.log(tabArr[i].title); });

into the body of turnTabRed the title of the new tab would not be printed into the console, which suggested that the script was being injected too early, so I tried delaying the injection with setTimeout and when that failed, I tried listening for the status-complete event:

function turnTabRed(tab)
{
  chrome.tabs.onUpdated.addListener(
    function(tabUpdatedId, changeInfo, tabUpdated)
    {
      if (tabUpdatedId == tab.id && changeInfo.status && 
                                    changeInfo.status == 'complete')
        chrome.tabs.executeScript(
          tabUpdatedId,
          {code: 'document.body.style.backgroundColor="red"'});
    });
}

which also failed. Calling (*) after waiting with setTimeout did print the new tab's title along with all the others though.

What's wrong? How can I create a new tab, load an HTML page and then turn its background red?

asnr
  • 1,692
  • 1
  • 14
  • 17

1 Answers1

5

The problem is that you cannot inject scripts into chrome-extension://* pages (which your blankpage.html is).

For example, change

{url: chrome.extension.getURL("blankpage.html")} 

to

{url: "http://www.google.com"}

in your original codeblock and it will change the background to red. As far as I know there is no way around injecting into chrome-extension://* pages (I would assume the reason for this is that it is a giant security concern). I'm not sure what your extension is trying to do, but injecting into a "live" page should work...maybe you can create some API to generate a new "blankpage" on your server whenever the chrome.runtime.onMessage.addListener fires?

EDIT

So you can't inject stuff into chrome-extension://* pages, but you can pass messages to them and use some subset of chrome API's inside those new pages as mentioned below. So using message passing you will be able to do exactly what you want (modify the new page), albeit in a roundabout way. Here is a really simple proof of concept that works for me:

eventPage.js:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) 
  {
    chrome.tabs.create({url: chrome.extension.getURL("blankpage.html")}, turnTabRed);      
  });

function turnTabRed(tab)
{
  chrome.tabs.sendMessage(tab.id, {"action" : "setBackground"});
}

blankpage.js:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if(request.action == "setBackground") document.body.style.background = "red";
  });
asnr
  • 1,692
  • 1
  • 14
  • 17
berrberr
  • 1,914
  • 11
  • 16
  • Running `chrome.extension.getURL("blankpage.html")` in the console returns `chrome-extension:///blankpage.html` (not `chrome://...`) and https://developer.chrome.com/extensions/match_patterns.html uses `chrome-extension://*/*` as an example pattern; however if I put that pattern in the manifest under `permissions` chrome issues a warning: "Permission 'chrome-extension://*/*' is unknown or URL pattern is malformed". Putting it under the `matches` property of `content_scripts` also yields an error on loading the extension. Can you point to some documentation that clarifies this? – asnr Jan 09 '14 at 06:22
  • I'm still not able to inject into `blankpage.html` but I can pass messages from `blankpage.js` (the JavaScript for the HTML page) to the extension page to dynamically modify `blankpage.html` (which was my original goal) using `chrome.runtime.sendMessage()`, for example: `chrome.runtime.sendMessage({}, function(response) { document.body.style.backgroundcolor="red"; });`. If you amend your answer so it suggests this as a workaround I'll be glad to accept it. – asnr Jan 09 '14 at 07:41
  • Ahh interesting...is `blankpage.js` a javascript file linked from the html of `blankpage.html`? Or a content script? If you are able to inject content scripts into `chrome://*` pages, then perhaps message passing to content script of the new page in the callback of the tab creation is a viable solution? This is a pretty interesting problem... I'll look into some more solutions when I get a chance :). – berrberr Jan 09 '14 at 14:36
  • Sorry I wasn't clear, `blankpage.js` is linked from the html of `blankpage.html`. It appears that javascript linked from an html page that is included in an extension (and not part of an event/background page or content script) has access to some subset of the `chrome.*` API - at least it can call `chrome.runtime.sendMessage()`. This suffices for my purposes - the javascript linked from the html page can take responsibility for displaying data it gets passed from the event page in a message. I still can't inject into the page either automatically or programmatically - see my first comment. – asnr Jan 09 '14 at 23:37
  • I've updated the answer with some new code that is working for me. – berrberr Jan 10 '14 at 01:36
  • @berrberr, hey, I just tried if you starting the message passing from background page, `blankpage.html` won't receive the message; however, if you start message passing from `blankpage.html` and execute action in the response, everything works well, any ideas? I have put my thoughts in this answer: http://stackoverflow.com/questions/38057056/injecting-javascript-into-newly-created-tab-in-chrome-extension/38065463#38065463 – Haibara Ai Jun 28 '16 at 01:02