Building your own Javascript library (part 2)

Goal

In this second installment of my 3-part library-building journey, I’m going to make the core plugin for the library. This plugin will contain utility methods. Stuff that can be used, either by other plugins, or just by regular Javascript code. So far, I haven’t needed many utility methods, so this chapter will be rather short. If you’re ready, read on!

Update 18-08-2010: code below is deprecated. “loadJs” and “loadOnce” have been merged now in the repository.

Creating the Core plugin

So far, the only functionality I have needed, was dynamically loading other Javascript files on a page. jQuery is perfectly capable of doing just that. I’m just going to wrap it up in a method or two.

First, let’s start off with the base of my plugin. A self-contained, anonymous function that will be executed immediately.

(function(){
    var core = {

    };

    // Let's put this in the 'core' namespace of TAG:
    Tag.extend("core",core);
})();

In my previous blog post, there were some extra’s there: settings and an init method. I won’t be needing those at this moment, so I left them out.

There are two important things I need when dynamically loading other Javascript files. I want to be able to do something when the file is loaded. And in some cases I want to make sure that a file is loaded only once. The reason for that last feature is that when I want to create self-contained partials, I don’t want to load the same file over and over again when that partial is put on my page more than once.

That being said, the first method will accept a file URL and optionally a callback. The callback allows me to execute code after the file was loaded.

(function(){
    var core = {
        /**
         * Loads a JS library via Ajax and execute an optional callback function
         *
         * @param url String - The location of the script
         * @param callback Function - Optional callback to execute after script was loaded
         * @return Object - Core plugin for chainability
         */
        loadJS:function(url,callback){
            if (typeof callback === "undefined") {
                callback = function(){};
            }

            // load it via Ajax
            $.getScript(url,callback);
            return this;
        }
    };

    // Let's put this in the 'core' namespace of TAG:
    Tag.extend("core",core);
})();

As you can see, I just used jQuery’s getScript() method, so all restrictions apply. The return value of the method is the current object or scope. This allows you to chain multiple methods, like this:

	Tag.core.loadJS("/path/to/first.js").loadJS("/path/to/second.js").someOtherFunctionFromCore();

This keeps it all nice and tidy. You can read up on chainability in Javascript here on Javascript Ant. Chaining methods is commonly used in PHP as well. I like that principle, because it makes your code shorter and more readable.

Now that I can load 1 file, I want to be able to make sure it’s loaded only once. For that the plugin needs an extra method, and a list to put the loaded libraries in.

(function(){
    var core = {
        /**
         * @var array - List of loaded JS scripts
         */
        libraries:[],

        /**
         * Loads a JS library via Ajax and execute an optional callback function
         *
         * @param url String - The location of the script
         * @param callback Function - Optional callback to execute after script was loaded
         * @return Object - Core plugin for chainability
         */
        loadJS:function(url,callback){
            if (typeof callback === "undefined") {
                callback = function(){};
            }

            // load it via Ajax
            $.getScript(url,callback);
            return this;
        },

        /**
         * Loads a JS library once via Ajax, with optional callback
         *
         * @param url String - The location of the script
         * @param callback Function - Optional callback to execute after script was loaded
         * @return Object - Core plugin for chainability
         */
        loadOnce:function(url,callback){
            if (typeof callback === "undefined"){
                callback = function(){};
            }

            if ($.inArray(url,this.libraries) == -1) {
                // load JS:
                this.loadJS(url, callback);

                // append to list:
                this.libraries.push(url);
            } else {
                // just execute the callback when the library is already loaded
                callback();
            }
            return this;
        }
    };

    // Let's put this in the 'core' namespace of TAG:
    Tag.extend("core",core);
})();

The “loadOnce” method takes the same input as the “loadJS” method. But as a bonus, it keeps track of the files it has loaded. When some code is trying to load a file for the second time, then there is no penalty. The callback will just be executed, just as if it were the first time the file was loaded.

Usage

I’ll just give you some examples. Simplest case, you just want to load a file:

	Tag.core.loadJS("/path/to/file.js");

Load a couple of files:

	Tag.core.loadJS("/path/to/file.js");
	Tag.core.loadJS("/path/to/anotherfile.js");

	// OR
	Tag.core.loadJS("/path/to/file.js").loadJS("/path/to/anotherfile.js");

Load a file, and then execute some code:

	Tag.core.loadJS("/path/to/file.js",function(){
		alert("File is loaded");
	});

Load a file after another file was loaded:

	Tag.core.loadJS("/path/to/file.js",function(){
		Tag.core.loadJS("/path/to/anotherfile.js");
	});

Load a plugin, and then set the correct settings for it:

	Tag.core.loadJS("/path/to/myPlugin.js",function(){
		Tag.myPlugin.setConfig({
			url:"http://www.example.com/",
			selectors:{
				exampleLink:".example"
			}
		});
	});

The list could go on forever. All these examples are also valid for the “loadOnce” method.

Next

In the last part of this series, I’ll create my Pubsub plugin: an event dispatcher. For this, I will have to modify the base class a bit, as I want to make use of Dependency Injection. But that’s for tomorrow.

All code is still available on my Codaset account here: http://www.codaset.com/theanalogguy/the-analog-guy-javascript-library

Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>