views:

45

answers:

1

I am building a javascript widget that should load asynchronously.

Problem is that there can be more than 1 of these widgets on the page and that the widget should be initialized by sending it an option array via {}.

What is the best way to accomplish this? I heard that simply setting onload or onreadystatechange does not work in all browsers.

I've checked out the digg widget, but I can't really comprehend what they're doing, could anyone take a look at that?

Here's some of their code:

(function () {
var s, s1, diggWidget = {
    id: "digg-widget-1282651415272",
    width: 300,
    display: "tabbed"
};
if (window.DiggWidget) {
    if (typeof DiggWidget == 'function') {
        new DiggWidget(diggWidget);
    } else {
        DiggWidget.push(diggWidget);
    }
} else {
    DiggWidget = [diggWidget];
    s = document.createElement('SCRIPT');
    s.type = 'text/javascript';
    s.async = true;
    s.src = 'http://widgets.digg.com/widgets.js';
    s1 = document.getElementsByTagName('SCRIPT')[0];
    s1.parentNode.insertBefore(s, s1);
}
})();

So, if the DiggWidget is already available (loaded earlier due to multiple instances), it makes a new widget if DiggWidget is a function, otherwise DiggWidget is used as an array and the current settings are pushed to it.

First, why would DiggWidget ever be a function?

If the widget is the only one (or first), the script tag is added asynchronously, no callbacks are defined.

Then, looking at widgets.js they do this:

At the top:

(function () {
var A;
if (window.DiggWidget) {
    if (typeof DiggWidget != "function") {
        A = DiggWidget
    } else {
        return
    }
}

At the bottom:

    if (A) {
    while (A.length) {
        new DiggWidget(A.shift())
    }
}

Now I don't quite understand this. Is DiggWidget (the array) available to that .js ? It's in a anonymous function. So if I include such a script twice, wouldn't DiggWidget be a new instance every time?

Or am I completely in the wrong on this? Sorry if so. If there's any better methods to have a callback with multiple instances of the script, please do tell.

+2  A: 

First, why would DiggWidget ever be a function?

It will become a function when the asynchronous script loads and executes

Is DiggWidget (the array) available to that .js

Yes, window.DiggWidget is global so it's available to that script.

The way the widget works is rather simple.

If the DiggWidget script has not been loaded yet, then window.DiggWidget will not be a function. Initially it will be an undefined variable so the else block

} else {
    DiggWidget = [diggWidget];

executes and defines it as an array. From now onwards and until the widget script loads, it will be defined as an array.

Now until the DiggWidget script loads asynchronously, keep pushing all initialization objects {..} to an array of the same name - window.DiggWidget.

When the script is loaded, before it overtakes the global DiggWidget variable it sees the objects in that array, and safely records it somewhere else. Then takes over the DiggWidget name, loops through each object, and initializes the widget for each.

Here's the full embed code annotated with comments.

User code

(function () {
var s, s1, diggWidget = {
    id: "digg-widget-1282651415272",
    width: 300,
    display: "tabbed"
};
// either the external widget script has already loaded, or there is more than
// one widget to be embedded on the page, and the previous widget's embed code
// defined this variable
if (window.DiggWidget) {
    // the external widget script has been loaded asynchronously 
    // because DiggWidget is a function. Can directly create a new object.
    if (typeof DiggWidget == 'function') {
        new DiggWidget(diggWidget);
    }
    // a previous widget's embed code defined this global array. Remember the
    // widgets initialization settings for when the external script loads.
    else {
        DiggWidget.push(diggWidget);
    }
}
// the external widget script has not loaded yet and
// this is the first widget ever to be embedded on the page
else {
    // DiggWidget does not exist at this point. So make it an array
    // and store the first widget's config object in it
    DiggWidget = [diggWidget];
    s = document.createElement('SCRIPT');
    s.type = 'text/javascript';
    s.async = true;
    s.src = 'http://widgets.digg.com/widgets.js';
    s1 = document.getElementsByTagName('SCRIPT')[0];
    s1.parentNode.insertBefore(s, s1);
}
})();

Widget code (at the top)

(function () {
var A;
// global DiggWiget is defined. it will either be an array if 
// the widget code hasn't loaded yet, or a function if it has
if (window.DiggWidget) {
    // it's an array, so keep that array somewhere safe
    // because we are gonna take over the DiggWidget variable purdy soon
    if (typeof DiggWidget != "function") {
        A = DiggWidget
    }
    // window.DiggWidget must be a function
    // there is no widget to initialize, just return
    else {
        return
    }
}

(at the bottom)

    // A is the array of widget settings we backed up a little earlier
    if (A) {
    // loop through each config object and create the actual
    // widget object
    while (A.length) {
        new DiggWidget(A.shift())
    }
}
Anurag
Ah ok, thanks. I thought DiggWidget was a local variable, different from window.DiggWidget. But since it's not initialized (no var = ) I guess it's a global variable. Makes sense. Thanks! (would upvote but this is a new account)Btw, isn't it wrong not to initiliaze that DiggWidget {} somewhere?
Wesley
@wesleyh - Not sure if I understand your question, but they are storing that local `diggWidget` config object `{..}` in the global `DiggWidget` array. I know it's kinda confusing :) Added the widget embed code with comments for more detail.
Anurag
Hot damn, thanks for all the commenting. Explains it very clearly. What I was saying is that I initially thought DiggWidget = [diggWidget]; would create a local variable because of the anonymous function it is in, but it's global due to not having the var =Anyway thanks a ton!
Wesley
lol.. I wanna write a embeddable widget myself, so it was helpful to understand how Digg's worked and commenting it myself was part of that understanding :)
Anurag