4

Is it possible to inject a javascript file into the DOM and immediately execute it ? I wish to invoke javascript functions within the page/DOM. A single content script will not work because of the isolated worlds. A background page is required to use chrome.tabs.executeScript().

Simple Example:
DOM javascript

function sayHello(){
  alert('Hello World');
}

Javascript file to inject

console.log('Injection complete. Now calling DOM script.');
sayHello();
Kim
  • 2,747
  • 7
  • 41
  • 50
  • 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 Mar 28 '12 at 14:29

1 Answers1

5

Here's my two favorite ways...

// Executing an anonymous script
function exec(fn) {
   var script = document.createElement('script');
   script.setAttribute("type", "application/javascript");
   script.textContent = '(' + fn + ')();';
   document.documentElement.appendChild(script); // run the script
   document.documentElement.removeChild(script); // clean up
}

script = function() {
//sayHello();
alert('hello');
}

exec(script);

// Append a script from a file in your extension
function appendScript(scriptFile) {
   var script = document.createElement('script');
   script.setAttribute("type", "application/javascript");
   script.setAttribute("src", chrome.extension.getURL(scriptFile));
   document.documentElement.appendChild(script); // run the script
}

appendScript('someFile.js');

Also chrome.tabs.executeScript() can be used from a browser/page action popup and the above code works in a content script aswell.

EDIT
Thanks to comments by @renocor, here's a variation of the first method that allows you to send arguments to the injected function....

function exec(fn) {
    var args = '';
    if (arguments.length > 1) {
        for (var i = 1, end = arguments.length - 2; i <= end; i++) {
            args += typeof arguments[i]=='function' ? arguments[i] : JSON.stringify(arguments[i]) + ', ';
        }
        args += typeof arguments[i]=='function' ? arguments[arguments.length - 1] : JSON.stringify(arguments[arguments.length - 1]);
    }
    var script = document.createElement('script');
    script.setAttribute("type", "application/javascript");
    script.textContent = '(' + fn + ')(' + args + ');';
    document.documentElement.appendChild(script); // run the script
    document.documentElement.removeChild(script); // clean up
}

script = function(what, huh, nah, yeah) {
    console.debug(arguments);
    console.debug('what=', what);
    console.debug('huh=', huh);
    console.debug('nah=', nah);
    console.debug('yeah=', yeah);
    if (typeof yeah=='function') yeah();
}

exec(script, 'meh', ['bleh'], {
    a: {
        b: 0
    }
}, function(){
    alert('hi');
});

console.debug('No arguments');

exec(script);
PAEz
  • 8,366
  • 2
  • 34
  • 27
  • I only remove the script on the anonymous function way because its only going to get run once anywayz and so its of no use anymore and so best to clean up...otherwise your going to keep adding script tags every time you use it. – PAEz Mar 29 '12 at 19:42
  • In the first way, if you want to pass variables to the function: function exec(fn, opts) { if (!opts) var opts = {}; var script = document.createElement('script'); script.setAttribute("type", "application/javascript"); script.textContent = '(function(){var opts = ' + JSON.stringify(opts) + ';(' + fn + ')();})();'; ... } Useful... for me at least. – Parziphal Apr 19 '13 at 23:56
  • @renocor Awesome idea, definitely useful. I had a look at the idea and did it a little different to you, could you check it out ( https://gist.github.com/PAEz/5426120#file-attach-function-with-arguments ) and if you like it Ill add it to the answer (your way may be better....I dont know). Thanks alot for your input. – PAEz Apr 20 '13 at 14:22
  • @renocor Just updated it so you can pass a function as an argument aswell ( https://gist.github.com/PAEz/5426120#file-attach-function-with-arguments )....cool – PAEz Apr 20 '13 at 14:34
  • Yeah, that's even better. Actually I didn't know about the "arguments" var, that's why I only passed one argument, hehe. – Parziphal Apr 21 '13 at 15:02