3

I am trying to develop a Chrome extension to open Office documents stored in Confluence in a new tab using the IE Tab extension.

In the 'View Page Attachment' screen, there is an 'Edit in Office' link for Office file attachments. The link has a click event that creates a new instance of a URLLauncher, which is used to open the document. This feature is not supported in Chrome, so I want to add my own URLLauncher prototype into the web page to make it work.

In short, this is my idea:

  1. Create a Chrome extension with a content script that injects a URLLauncher prototype into the 'View Page Attachment' page (I don't know if this is the right approach, so I am open to suggestions).
  2. When the user clicks on the 'Edit in Office' link, the URLLauncher.open method opens the file attachment in a new tab by calling the IE Tab extension.

I can see the 'Hi there!' alert every time I load a web page, and that confirms that content.js is being injected. Nevertheless, the URLLauncher is not available in the web page. I think this is because the global window object of the content script is distinct from the page/extension's global namespace (i.e., window.URLLauncher is undefined). How could I reorganize my code to overcome this obstacle?

These are my files:

manifest.json

{
   "manifest_version": 2,
   "background": {
      "scripts": [
         "background.js"
      ]
   },
   "content_scripts": [ {
      "js": [ "content.js" ],
      "matches": [ "<all_urls>" ]
   } ],
   "description": "This is a test extension",
   "permissions": [
      "tabs", "http://*/*", "https://*/*"
   ],
   "name": "Test extension",
   "version": "1.0.0"
}

background.js

chrome.tabs.executeScript(null, { 
   code: "document.body.appendChild(document.createElement('script')).src='" + 
   chrome.extension.getURL("content.js") + "';" 
}, null);

chrome.runtime.onMessage.addListener(
   function(request, sender, sendResponse) {
      console.log(sender.tab ?
            "from a content script:" + sender.tab.url :
            "from the extension");
      if (request.id == "doUrlLaunch") {        
         chrome.tabs.create({ url: request.nUrl, selected: true });
         sendResponse({result: "goodbye"});
      }
   }
);

content.js

var prefixUrl = 'chrome-extension://hehijbfgiekmjfkfjpbkbammjbdenadd/iecontainer.html#url=';
alert('Hi there!');
function URLLauncher() {

}

URLLauncher.prototype = {  
   open : function(urlStr) {
      var newUrl = prefixUrl + 'https://host.com' + encodeURI(urlStr);
      chrome.runtime.sendMessage({id: "doUrlLaunch", nUrl: newUrl}, function(response) {
      });
   }
}

Thanks in advance.

UPDATE 1

I edited the files following the instructions given by Rob W and this page ('Message Passing'); now the code is injected in the page itself, but a major problem still remains. The actual JS code sends a message to the content script, but the message is not caught by the listener, so the new tab is not created and the callback function does not receive a response; the error message I got: Error in event handler for (unknown): TypeError: Cannot read property 'success' of undefined.

These are the updated files:

manifest.json

{
   "manifest_version": 2,
   "content_scripts": [ {
      "js": [ "content.js" ],
      "matches": [ "<all_urls>" ]
   } ],
   "web_accessible_resources": [ "script.js" ],
   "description": "This is a test extension",
   "permissions": [
      "tabs", "http://*/*", "https://*/*"
   ],
   "name": "Test extension",
   "version": "1.0.0",
   "externally_connectable": {
      "ids": ["*"],
      "matches": ["*://*.hostname.com/*"]
   }
}

content.js

var s = document.createElement('script');
s.src = chrome.extension.getURL("script.js");
s.onload = function() {
    this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);

chrome.runtime.onMessage.addListener(
//Unreachable code!
   function(request, sender, sendResponse) {
      console.log(sender.tab ?
            "from a content script:" + sender.tab.url :
            "from the extension");
      if (request.id == "doUrlLaunch") {        
         chrome.tabs.create({ url: request.nUrl, selected: true });
         sendResponse({result: "goodbye"});
      }
   }
);

script.js

var prefixUrl = 'chrome-extension://hehijbfgiekmjfkfjpbkbammjbdenadd/iecontainer.html#url=';
function URLLauncher() {

}

URLLauncher.prototype = {  
   open : function(urlStr) {
      var newUrl = prefixUrl + 'https://hostname.com' + encodeURI(urlStr);
      chrome.runtime.sendMessage({id: "doUrlLaunch", nUrl: newUrl}, function(response) {
          if (!response.success)
              console.log('Something went wrong...');
      });
   }
}
Community
  • 1
  • 1
YahooER YER
  • 67
  • 1
  • 9
  • 1
    possible duplicate of [Building a Chrome Extension - Inject code in a page using a Content script](http://stackoverflow.com/questions/9515704/building-a-chrome-extension-inject-code-in-a-page-using-a-content-script) – Rob W Sep 25 '13 at 08:06
  • Thanks for your help, Rob W. I updated my code, but it seems that the injected code cannot send the message to the content script, as I explain in detail above. I would appreciate your insights. – YahooER YER Sep 25 '13 at 20:18
  • 5
    Injected scripts behave as if they originate from the page they're injected in. Such scripts cannot use any of the Chrome extension API. To "talk" with the background script, the injected first need to send a message to the content script, which in turn send a message to the background page. For a full example on sending a message from the injected script to the background, see http://stackoverflow.com/a/13779769/938089. For another example of communicating between injected script and content script, see http://stackoverflow.com/a/10527809/938089. – Rob W Sep 25 '13 at 20:24

1 Answers1

0

Not sure if you're still interested in an answer, but in your edited files your problem is where your listener sits.

  1. chrome.runtime.sendMessage does not reach content scripts; it is intended for extension pages. Message passing to content scripts works through chrome.tabs.sendMessage, but this is irrelevant for this task.

  2. Content scripts can't call chrome.tabs as they do not have the required API access.

A solution would be to call a background script, that can receive those messages and can call the required API.

Therefore, you need a third script, taking out this code from content.js:

// background.js
chrome.runtime.onMessage.addListener(
   function(request, sender, sendResponse) {
      console.log(sender.tab ?
            "from a content script:" + sender.tab.url :
            "from the extension");
      if (request.id == "doUrlLaunch") {        
         chrome.tabs.create({ url: request.nUrl, selected: true });
         sendResponse({result: "goodbye"});
      }
   }
);    

And modify your manifest:

  "background": { "scripts": [ "background.js" ] },
Xan
  • 74,770
  • 16
  • 179
  • 206