< Pixel Perfect />
Modernizr & Plugin Detection

Modernizr is a popular javascript library that helps you build the next generation of html5 and css3-powered websites. If your not familiar with it and your a developer, I recommend you visit there website.

Apart from its amazing feature detection abilities I’ve decided to play with its api a little. In a recent project of mine I wanted to seporate my javascript logic into 2 main categories to help keep clean seporation in my MVC app. My application varies in script(plugin) loading on each page. So I decided to use Modernizr’s feature detection abilities to load jquery plugins to decrease the overhead loading time on my pages.

Modernizrs api contains an method called addTest().


    Modernizr.addTest(str, fn)
    Modernizr.addTest(str, bool)
    Modernizr.addTest({str: fn, str2: fn2})
    Modernizr.addTest({str: bool, str2: fn})

I’ll add a class name to any element on the page, I’ll run a test. If Modernizr finds that specific class name, it means that that feature(plugin) exsists and needs to load its dependencies.

First I’ll add the new features to Modernizr:


/* Adding any of the class names to any element on the page 
   will load the dependencies for that plugin. */

Modernizr.addTest('pluginSlider', $(".pluginSlider").length == 1);
Modernizr.addTest('pluginTipped', $(".pluginTipped").length == 1);
Modernizr.addTest('pluginFancybox', $(".pluginFancybox").length == 1);
Modernizr.addTest('pluginSuperfish', $(".pluginSuperfish").length == 1);
Modernizr.addTest('pluginIsotope', $(".pluginIsotope").length == 1);

Next run the tests that determine what plugins are on the page.


Modernizr.load([
    {
        test: Modernizr.pluginSlider, // This will be truthy or falsy
        nope: ['/js/libs/slides.min.jquery.js']
    },
    {
        test: Modernizr.pluginTipped,
        nope: ['/js/libs/spinners.js', '/js/libs/tipped.js', '/css/tipped.css'],
        callback: function (url, result, key) { 
                      Modernizr.load([{ 
                          test: Modernizr.canvas, nope: ['/js/libs/excanvas.js']
                      }]); 
                  }
    },
    {
        test: Modernizr.pluginIsotope,
        nope: ['/js/libs/jquery.isotope.min.js']
    }
]);

Great! Scripts will now load if a class name such as “.pluginSlider” is on some element. Except one more thing that needs to be addressed. I want to separate the page specific logic. I like to develop using closures so what I can do is initiate whatever my page js object is. By adding the complete() method to the end of my tests, I can initiate my page object which has all my page specific logic in it.


Modernizr.load([
    {
        test: Modernizr.pluginSlider, // This will be truthy or falsy
        nope: ['/js/libs/slides.min.jquery.js']
    },
    {
        test: Modernizr.pluginTipped,
        nope: ['/js/libs/spinners.js', '/js/libs/tipped.js', '/css/tipped.css'],
        callback: function (url, result, key) { 
                      Modernizr.load([{ 
                          test: Modernizr.canvas, nope: ['/js/libs/excanvas.js']
                      }]); 
                  }
    },
    {
        test: Modernizr.pluginIsotope,
        nope: ['/js/libs/jquery.isotope.min.js'],

        /* HERE IS THE INIT OBJECT */
        complete: function () {
            /* Run this after everything in this group has downloaded
            and executed, as well everything in all previous groups */

            /* Each page should contain the object myapp else we just 
               fall back to an empty object */

            if (typeof myapp == 'function') {
                var app = new myapp();
                app.init();
            }


        }
    }
]);

Now on my page all I need to have is the closure model that initiates. To understand javascript closures view my other post here.


var myapp = (function () {

    var root = this;
    
    root.init = function(){
        /* CALL YOUR PLUGINS HERE */
        $("pluginSlider").slider();
    };

});

Summary: Clean separation of global dependencies and page specific logic. Improved performance by loading only scripts that are actually needed.

JavaScript Closures

JavaScript objects are at the heart of every application. Unfortunately theres alot of misuse of objects. Before diving into this brief explination I want to start by saying “If you understand the framework, the rest is just syntax”. Dont get caught up on trying to understand all of the syntax.

Think of an object as a container. That containers content should be relevant to its purpose. A container with a collection of properties and methods.

Lets use the car example. To begin were going to create a model that will represent what a car is. Then we will actually create a car when finished. The car being the JavaScript object:


var car= (function(){    /* I'm inside of the car. */    });

A car has several properties like fuel level, tire pressure. It may even have safety features like traction control or airbags.


var car = (function(){

    var root= this;

    root.properties = {
        fuelLevel: "100%",
        tirePressure: "high",
        headLights: 'on',
        engine:"off"
    };

});

The car now contains the properties we can later use. Cars aren’t just for show though. They move, accelerate, brake. Maybe even have a few other features like heat or sunroof.


var car = (function(){

    var root= this;

    root.properties = {
        fuelLevel: "100%",
        tirePressure: "high",
        headLights: 'on',
        engine:"off"
    };

    root.actions = {
        start:function () { root.properties.engine = "on"; alert("car started"); },
        drive:function () { alert("driving away"); },
        turn:function () { },
        signal:function () { }
    };

});

Now that we have finished our closure, lets use the car!


var myCar= new car();

My myCar object is now using the car model we designed. Let’s start it up.


if(  myCar.properties.fuelLevel > 0 ) {
    
    myCar.actions.Start();

}

Now lets drive our car. But wait. You can’t drive a car that’s not started so let’s check to see if it’s started first.


if( myCar.properties.engine == "on" ) {
    
    myCar.actions.drive();

}

Summary: 
By enclosing related javascript properties and methods, your enabling better reuse of your code. This will in the end improve performance.

Have a little success, and theres always a fool to tell you how talented you are.