4

Not sure if this is the right approach of if this even a "good" question, but I'm loading a javscript as part of a plugin style architecture and I have the following problem:

If a particular node has a reference to a plugin, I want to load that plugin per the url provided via the json description of that plugin. the description will have something like the following (or a functional equivalent):

{
  "pluginSrc" : "http://mysite.com/plugins/1204.js",
  "configData" :
    {
      "someData", "someValue",
      "someMoreData", "etc"
    }
}

When the javascript loads, I'll have an onload handler that will check to see if a function name exists on the window object and if so, create a new instance of that function and pass it the config data (more or less), this part works very well, with a few exceptions.

Sometimes I do not have a reference to the name of the function that I need to invoke and there is no way to get it from the json. What would be ideal, is if I could tell which function was added to the window object on the script's onload callback and create an instance of that function. Is this possible? I only need to worry about modern browsers, particularly webkit. Apologies if the question isn't clear, I'd be happy to clarify, but producing a fiddle might be difficult as there's a lot of code to write to reach a minimal example.

What I'm thinking about so far is to create some kind of global variable in the loaded script file like

function MediaAnalytics(){};
var LoadedClass = MediaAnalytics;

and just creating an instance of LoadedClass when the script is loaded, but this falls short of a panacea because I will not always be writing the plugin.

EDIT: These scripts will most likely not be from the same domain.

2
  • What if you made a blank iframe, loaded the JS in there, and then copied the function(s) from the iframe's window to the main window? (I don't know if that works, just throwing it out there) Commented Mar 6, 2012 at 18:42
  • 1
    Interesting idea and it might work in a lot of contexts. Unfortunately this project exports to Android / iPhone via phonegap and iframes can cause all kinds of problems that I'd rather avoid. Great suggestion though! Commented Mar 6, 2012 at 18:57

2 Answers 2

3

You haven't specified how you load the script file. I hope that you will get the script text in onload handler.

Anyway I am explaining how to do this using jQuery.getScript. In this you will get the script text in success handler as data. So you can use this to get the loaded Function.

Suppose the script file dynamic.js contains

function MediaAnalytics(){};

load it using getScript

$.getScript("dynamic.js", function (data, textStatus, jqxhr) {
    var NewFunction;
    eval("NewFunction = " + data);
    alert(NewFunction.name); // here you will get alert showing MediaAnalytics
});

Here NewFunction is MediaAnalytics. It will be the second execution of the script as getScript invokes the success handler after executing it and adding it to window object. You can give new NewFunction() to instantiate.

If you don't prefer using eval, another way is using a RegEx to find the name of the Function

$.getScript("dynamic.js", function (data, textStatus, jqxhr) {
    alert(data.match(/function(.*)\(/)); 
});

This will alert function MediaAnalytics( . match returns an array. The name of the function can be retrieved from it.

You can use a better RegExp to extract the exact function name and get the property of window object.

EDIT: (no jquery)

Or you can load your script as text and add to window as a script tag in your onload handler. There you can use your trick even if the plugin-script is not yours.

var dynamicjs = "function MediaAnalytics(){};";  // script loaded as text

var modified = "LoadedClass = " + dynamicjs;

var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.textContent= modified;  // innerText in some browsers
head.appendChild(script);

alert(LoadedClass);  // LoadedClass is MediaAnalytics
Sign up to request clarification or add additional context in comments.

9 Comments

brilliant. going to try that now. I didn't want to get overly specific with the load method because I have some flexibility there.
I'm seeing a response in my http sniffer, but "data" is tracing out undefined. jsfiddle.net/hyperthalamus/x274C any idea why that might be?
about the non jQuery approach, does script.textContent || script.innerText produce the contents of the js file as a string or is that for assignment only? I'm not able to get that to work either unfortunately.
@Shane. Because of same origin policy. Will be the scripts from other domain/domains ? . In that case this solution will need modification.
Ah, yes, these scripts can be loaded from anywhere. I'll modify my original question.
|
1

I would suggest making it required to have the entry-function's name in the json. It would be the least hacky way to go about it in my opinion.

However, something you could try would be to iterate all the properties of window. If you find a new function in window after loading the script, you could assume that's the one which just got loaded.

Something like this..

var windowMembers = [];
function loadScript() {
    for(var m in window) {
        windowMembers.push(m);
    }

    //load your new script
    //some code here to load the script

    //put an onload handler...
    s.onload = function() {
        for(var m in window) {
            if(windowMembers.indexOf(m) == -1) {
                //window[m] was added after the script loading began
                //call it:
                window[m]('blah blah');
            }
        }
    }
}

To be safe you could optionally check if the new property is a function, eg.

if(typeof window[m] == 'function')

4 Comments

I think this is the closest thing I've seen so far. Is there any kind of callback you can add to "s" that will execute just before the script loads? One of the problems I have is this is a large codebase, plugins come from who knows where and I'm pretty sure there are other components or plugins that create window level functions. If I had some way of capturing that just before the script is instantiated I think that would work.
What if a plugin overrode a function from another plugin?
I would think no new instances of that class could be created. Not sure what it would do to the existing instances. While possible, that's not likely to happen given the environment and if it does, somebody in ops is likely to lose 4-5 hours pinpointing the problem. :)
@Jani Thanks again, this would be fine if it weren't for the initialization craziness. As such I won't be able to use it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.