views:

180

answers:

2

Making a Google Chrome extension and need to run a script after the head is loaded, because there are scripts in the head and I need them to run. And before the DOM is loaded, because there's an inlined script in there that I need to beat.

How would I do this? How do I detect when head loads?

+4  A: 

Just put it at the top of the <body> tag. Scripts execute where they are placed and will block the rest of the page, so a script at the top of the body will have awareness of everything in the head, but no awareness of the rest of the DOM, which is still loading. If you place it at the bottom of the <body> it will still be before DOMReady and before the page-load event, plus you should be able to access DOM elements that preceeded the script. One way this can be useful if you need to append scripts dynamically to the <head> -- you can't do that with a script that's inside the <head>, so you have to do it in the <body>.

[Edit] My answer can be applied generally to any HTML document, but Mohamed's answer applies more directly to Google extensions. I'd be inclined to take his answer ahead of mine, though both are probably correct.

Andrew
This is for an extension. I don't have access to the website itself and can't edit it server side. If I do it client side, by the time I put it on top of the body tag, all scripts will have run by then.
this is a dead end
+2  A: 

When you inject your content script, within the manifest you can state the "run_at" parameter to be "document_start", the files are injected after any files from css, but before any other DOM is constructed or any other script is run. More information can be found here: http://code.google.com/chrome/extensions/content_scripts.html#registration

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "css": ["mystyles.css"],
      "js": ["jquery.js", "myscript.js"],
      "run_at": "document_start"
    }
  ],
  ...
}

*Edited, added an example. One of the mutations event types could be used.

Example

manifest.json

{
  "name": "Content Script test",
  "version": "0.1",
  "description": "Content Script test",
  "content_scripts": [
    {
      "matches": ["http://*/*"],
      "js": ["cs.js"],
      "run_at": "document_start",
      "all_frames": true
    }
  ]
}

cs.js

document.addEventListener('DOMSubtreeModified', OnSubtreeModified, false);

function OnSubtreeModified(event) {
  console.log('Hello from extension!');
  document.removeEventListener('DOMSubtreeModified', OnSubtreeModified, false);
}

test.html (on the web somewhere)

<html>
<head>
  <script>
    alert('Hello from Web!');
  </script>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

Results

You will two alerts, in the order:

  1. Hello from web!
  2. Hello from extension!
Mohamed Mansour
This is what I'm using. But it runs before any of the scripts in head are run. So I'm trying to figure out how to detect when that is.
this is a dead end
I edited my answer and placed an example. You can take advantage of the run_at document_start to see what has been added or removed from the dom. For example, you could use another event named 'DOMNodeInserted' too.
Mohamed Mansour
Eh, that might not be good for your case because the scripts of the page are ran already. So if you have access to that webpage, place your JavaScript right after <body>
Mohamed Mansour
I appreciate the effort but this doesn't work for me because "Hello from extension!" is ran after all the scripts on the page, even the ones in the body have already ran. I don't have access to the webpage, that's why it's an extension.
this is a dead end