3

I'm trying to inject a function into a webpage via Chrome extension content script by:

function inject(code) {
    var actualCode = '(' + code + ')();';
    var script = document.createElement('script');
    script.textContent = actualCode;
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
}

var myObj = person;  // myObj/person is passed in from elsewhere
var fn = function() {
    alert(myObj.name);
};
inject(fn); // myObj undefined

My issue is, since fn is a function expression, I can't pass in myObj.personName. So my question is, how can I construct a function expression that includes a variable? Do I do some sort of string concatenation instead?

I also tried to pass the object to the function, as follows:

function inject(code, myObj) {
    var actualCode = '(' + code + ')(' + myObj +');';
    ...

But this did not work, and caused a "Uncaught SyntaxError: Unexpected identifier" error.

Related: Insert code into the page context using a content script

Community
  • 1
  • 1
gotta have my pops
  • 878
  • 4
  • 11
  • 22
  • 1
    _"since fn is a function expression, I can't pass in myObj.personName"_ - Why not? You can do this: `(function(param){...})(paramValue);` (so you should be able to modify your code to make something like that happen). – nnnnnn Dec 11 '12 at 22:28
  • It depends on the scope. If `myObj` is declared in the same scope as `inject`, it should work. – bfavaretto Dec 11 '12 at 22:29
  • @nnnnnn I tried doing something like that. If I do `var fn = (function(p){...})(param);` it'll execute the function instead of passing the actual function expression. I also tried doing something like `function inject(func, myObj) { var code = '(' + func + ')(' + myObj + ');'; ... }`, but that absolutely did not work, lol, it threw _Uncaught SyntaxError: Unexpected identifier_ – gotta have my pops Dec 11 '12 at 22:41
  • @bfavaretto Unfortunately, it's not defined in the same scope as inject. Everything is wrapped in a event listener function and myObj is passed from the event itself. – gotta have my pops Dec 11 '12 at 22:47

3 Answers3

3

Your approach was almost correct. The problem is that the following

var code = '(' + func + ')(' + myObj + ');'   // results in
var code = '(function(){})([object Object])'

To solve this, just use JSON.stringify:

var code = '(' + func + ')(' + JSON.stringify(myObj) + ');';
Rob W
  • 341,306
  • 83
  • 791
  • 678
  • I've updated [the answer at "Building a Chrome Extension - Inject code in a page using a Content script"](http://stackoverflow.com/a/9517879/938089?building-a-chrome-extension-inject-code-in-a-page-using-a-content-script), and added a section at the end which explains this method with more details. – Rob W Dec 11 '12 at 23:12
1

Try:

var actualCode = new Function( code )();
elclanrs
  • 92,861
  • 21
  • 134
  • 171
1

You can post messages in and back between event listeners using window.postMessage.

Inject code like this into the page

window.addEventListener('message', function messageInvoker(e) {
    if (e.data.extKey !== 'myKey') return; // some kind of check so you only worry about your own extension
    window[e.data.fn].apply(window, e.data.params);
}, false);

And from your extension,

window.postMessage({extKey: 'myKey', fn: 'userFunction', params: ['a','b','c']}, '*');
Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • The documentation on the Developer site is a little confusing. Can the messages posted from the embedding page to the extension access the page's execution environment variables? – gotta have my pops Dec 11 '12 at 23:24
  • You can pass transferable objects (read self contained) and most data types, i.e. _String_, _Number_ etc. also _ArrayBuffer_. If your object references another object or the environment it was in I'm not sure what happens. – Paul S. Dec 11 '12 at 23:43