0

The extension I am writing triggers a content script on the start of page load, using:

"run_at":   "document_start"

This works just fine. However, I need to "inject" something and then continue rendering the initial page. If my action script simply contains:

alert("Hello World");

The alert will fire and the page will continue rendering. In contrast if the action script contains:

document.write("<span>Hello World!</span>");

This will write "Hello World!" but will not continue rendering the page. I know that "document.write" is almost never a good tool, but it seemed like the right tool because (a) its writing BEFORE the rest of the DOM and (b) there are no elements in the dom to "change" to effectuate the injection.

I think that explains the situation fairly well. But I'm going to provide a little more context. Ultimately I want to "inject" an iframe that will load "in front" of the page in question. Trying to provide users of my extension with an alternative user experience for a particular website.

COMisHARD
  • 867
  • 3
  • 13
  • 36
  • I would recommend you to run your script at `document_end` and modify complete loaded `DOM` instead of trying to modify it 'in flight' – Serge May 31 '16 at 00:51
  • I don't see how this is a constructive comment. I'm asking HOW to do something. I fully agree that it is usually best to use the approach you suggest. But for my purposes it wont work. The page I am trying to load takes about 2 minute to fully load. The entire purpose of my script is to allow the user an interface to start doing certain things WHILE the page is loading. – COMisHARD May 31 '16 at 00:53
  • In my own opinion, you can have a good use on [Message Passing](https://developer.chrome.com/extensions/messaging). This related SO post - [Message Passing Example From Chrome Extensions](http://stackoverflow.com/questions/21766990/message-passing-example-from-chrome-extensions) might help. – Teyam May 31 '16 at 10:56
  • @Teyam How is that in any way relevant? – Xan May 31 '16 at 10:56
  • `In the case of "document_start", the files are injected after any files from css, but before any other DOM is constructed or any other script is run.` So, you are trying to modify `DOM` when it does not exist yet. – Serge May 31 '16 at 13:10
  • Running `document.write()` before the DOM is constructed is definitely not the way to go. It causes Chrome to open a new document that will not get any of the content of the requested page. (I believe that point 3 from the [document.write specification](https://www.w3.org/TR/2011/WD-html5-20110525/apis-in-html-documents.html#dom-document-write) might apply here.) DOM manipulation as suggested in Xan's answer works. – Petr Srníček May 31 '16 at 15:23

1 Answers1

0

Well, I don't see much point writing to the document before <body> even exists, but you can do this with DOM manipulation as opposed to document.write:

var el = document.createElement("span");
el.textContent = "Hello, World!";
document.documentElement.appendChild(el);

This will not block the subsequent DOM parsing.

If you want to conform to a standard page structure and add it to the body element, you can add a MutationObserver to wait for it (though this may not be better than "document_end" injection):

var observer = new MutationObserver(function(mutations) {
  mutations.find(function(mutation) {
    for (var i = 0; i < mutation.addedNodes.length; i++) {
      if(mutation.addedNodes[i].nodeName === "BODY") {
        var el = document.createElement("span");
        el.textContent = "Hello, World!";
        // Clunky way to prepend a node
        mutation.addedNodes[i].insertBefore(el, mutation.addedNodes[i].firstChild);

        observer.disconnect();
        return true; // Early termination of find()
      }
    }
  });
});
observer.observe(document.documentElement, {childList: true});
Xan
  • 74,770
  • 16
  • 179
  • 206