31

I'm trying to write a Chrome extension that will have a bar at the top of certain webpages. If I have my content script like this:

$('body').prepend('<div id="topbar"><h1>test</h1></div>');

everything looks good, but what I ultimately want is something like this:

$('body').prepend('<div id="topbar"></div>');
$('#topbar').load('topbar.html');

where topbar.html is:

<h1>test</h1>

When I change it to this, though, the webpage is clobbered. Most of the content disappears, and I just end up seeing some of the ads. I can't even see the 'test' header. I've checked to make sure there's no other 'topbar' id on the page. What's wrong?

John Bachir
  • 22,495
  • 29
  • 154
  • 227
Colin
  • 10,447
  • 11
  • 46
  • 54
  • Where is `topbar.html` located? Chrome-Extension or web-side? – mattsven Apr 13 '11 at 01:12
  • It's in the chrome extension's directory – Colin Apr 13 '11 at 01:13
  • Well, `.load` uses AJAX to load in files to elements, and I am pretty sure you cannot load via AJAX local chrome files. – mattsven Apr 13 '11 at 01:17
  • 2
    I just used code that looks almost identical to this.. I added "web_accessible_resources": [...] to my manifest.json file and it worked perfectly.. – Ads Mar 14 '14 at 13:06

4 Answers4

39

URL of a file inside an extenion folder has the following format:

chrome-extension://<ID>/topbar.html

You can get this path by running:

chrome.extension.getURL("topbar.html")

Now if you try to do:

$('#topbar').load(chrome.extension.getURL("topbar.html"));

it wouldn't let you because of cross-origin policy. Background pages don't have this limitation, so you would need to load HTML there and pass result to a content script:

content_script.js:

chrome.extension.sendRequest({cmd: "read_file"}, function(html){
    $("#topbar").html(html);
});

background.html:

chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
    if(request.cmd == "read_file") {
        $.ajax({
            url: chrome.extension.getURL("topbar.html"),
            dataType: "html",
            success: sendResponse
        });
    }
})

In a real world you probably would read topbar.html only once and then reuse it.

serg
  • 109,619
  • 77
  • 317
  • 330
  • 6
    The $.get(chrome.extension.getURL("topbar.html"), function(topbarContent){ ... }, 'html'); bit works fine for me - I don't see any cross-origin errors in the console. – Vlad Iliescu Dec 29 '11 at 15:49
  • 9
    Should specify `web_accessible_resources` in the manifest. See: http://developer.chrome.com/extensions/manifest.html#web_accessible_resources – Xiao Jia Oct 12 '12 at 03:48
  • are you sure @VladIliescu...? I mean... did you get it as html or some object? – gumuruh Sep 12 '19 at 10:18
  • Please note that the `getURL()` method is now deprecated. "Non-standart. Expect poor cross-browser support" according to [Browser support for Javascript APIs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_support_for_JavaScript_APIs#extension) – Dony Sep 07 '20 at 10:11
6

While the above solution does work, one thing to pay attention to is that you need to return true from the event handler so that the communication port can still be available after the $.ajax call succeeds.

see below for more information. https://code.google.com/p/chromium/issues/detail?id=307034

spider T
  • 61
  • 2
  • 1
  • 12
    If you want to expand on another person's answer it is best to leave a comment on their answer instead of making a second one. – ChargerIIC Sep 17 '14 at 13:55
5

Pure js solution.

In your manifest.json:

{
  "manifest_version": 3,
  # [...]
  "web_accessible_resources": [{
      "matches": ["<all_urls>"],
      "resources": ["topbar.html"]
  }]
}

In your content.js:

async function load_toolbar() {
  let newElement = new DOMParser().parseFromString('<div id="toolbar"></div>', 'text/html').body.childNodes[0];
  let toolbar_url = chrome.runtime.getURL("toolbar.html");

  document.querySelector("body").appendChild(newElement);
  document.getElementById("toolbar").innerHTML = await (await fetch(toolbar_url)).text();
}

load_toolbar();
fguillen
  • 36,125
  • 23
  • 149
  • 210
2

FYI, now in 2020, chrome.extension.onRequest is deprecated and causes an error when loading the extension. Instead, chrome.runtime.sendMessage should be used. For content.js, the code would now be:

chrome.runtime.sendMessage({cmd: "read_file"}, function(html){
    $("#topbar").html(html);
});

and for background.js the code would now be:

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if(request.cmd == "read_file") {
        $.ajax({
            url: chrome.extension.getURL("topbar.html"),
            dataType: "html",
            success: sendResponse
        });
       return true;
    }
})

be sure to note the 'return true' after the ajax, that tripped me up

  • Ensure to add, make sure to include "topbar.html" in web_accessible_resources of manifest.json https://developer.chrome.com/extensions/manifest/web_accessible_resources – Satya Kalluri Oct 14 '20 at 13:37