MooTools Class Creation and Organization

David Walsh | January 18, 2011

 

As web applications aim to become more dynamic, responsive, and feature-filled, they will inevitably need to include more JavaScript. As the amount of code increases, there is also an increase in the need to keep that code organized, extendable, and maintainable. The MooTools JavaScript framework provides you just that. This post will cover the basics of creating and organizing MooTools classes so that your web application's JavaScript will stay organized and extendable for years to come.

A Basic Overview of MooTools

MooTools is a compact, modular, Object-Oriented JavaScript framework designed for the intermediate to advanced JavaScript developer. MooTools allows you to write powerful, flexible, and cross-browser code with its elegant, well documented, and coherent API. MooTools is easy to learn and fun to code. The framework is used on sites small and large, including CNET, Bing, Gamespot, and Twitter..

Class Creation with MooTools

JavaScript does not provide native classes like PHP, Java, and most other object-oriented languages do. MooTools abstracts the prototypal inheritance pattern to create its own version of classes within the JavaScript language. This virtual "class" is globally available as the Class object.

There are numerous advantages to using MooTools classes, including:

  • organizing related functions within one encapsulating class
  • the ability to extend existing classes to create more powerful, goal-specific classes
  • portability: moving a class from one site to another is much easier than moving a copy-and-pasted snippet

Those are just a few of the advantages to using MooTools classes. Many more exist, which you will likely realize after creating your first MooTools class!

MooTools Class Structure

Before analyzing the different components of MooTools class, it's important that you see what a sample class looks like. The following is a class template that I've used for quite some time now:

var MyClass = new Class({

    //implements
    Implements: [Options,Events],

    //your options with default values
    options: {
        classOption1: 1, //defaults to 1
        classOption2: true //defaults to true
    },

    //constructor, runs upon instantiation
    initialize: function(argument1,argument2,options) {
        
        //mix the custom options with the default options from above
        this.setOptions(options);
    },

    //a method that does whatever I want
    myCustomMethod: function() {
        //do any here!
    },
    
    //another method that does whatever I want
    myOtherCustomMethod: function() {
        //do any here!
    }
});

This template serves as a great starting point for creating a new class as it provides the pivotal components: options, Implements, initialize, and a sample method. All of these components are provided to the Class object within one object but a few of them have special meaning.

Class Components: Option and Default Values

The most basic of MooTools Class components is the options property. The options property is an object with key/values for variable class properties:

var MyClass = new Class({

    //your options with default values
    options: {
        classOption1: 1, //defaults to 1
        classOption2: true //defaults to true
    },

    //more methods here...
});

Your class may provide as many options as you'd like for it to support but beware of including too many options as your class could quickly bloat or experience the dreaded scope creep. To gain more context and get a more realistic usage of the options object, let's consider the following options object which is currently used within MooTools' Request (formerly known as "Ajax") class:

var Request = new Class({

    options: {
        /* event callbacks -- what to do at certain parts of a request */
        onRequest: function(){},
        onLoadstart: function(event, xhr){},
        onProgress: function(event, xhr){},
        onComplete: function(){},
        onCancel: function(){},
        onSuccess: function(responseText, responseXML){},
        onFailure: function(xhr){},
        onException: function(headerName, value){},
        onTimeout: function(){},
        
        /* basic AJAX request options */
        user: '',
        password: '',*/
        url: '',
        data: '',
        headers: {
            'X-Requested-With': 'XMLHttpRequest',
            'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
        },
        async: true,
        format: false,
        method: 'post',
        link: 'ignore',
        isSuccess: null,
        emulation: true,
        urlEncoded: true,
        encoding: 'utf-8',
        evalScripts: false,
        evalResponse: false,
        timeout: 0,
        noCache: false
    },
    
    //more methods here...
});

As you can see, MooTools' Request class provides a wealth of options to allow you to customize just about every part of your AJAX request! Also note that each key within the options object provides a default value. Always set the default to the most likely value to avoid needing to set the option in subsequent instances of the class. Also note that options are named so that it's easy to know what they represent.

Options may be referenced within your class by this.options.optionName within any of the class methods. As a best practice, option values should not be modified by the class — they should be saved as new variable:

var MyClass = new Class({
    
    //your options with default values
    options: {
        classOption1: 1, //defaults to 1
        classOption2: true //defaults to true
    },
    
    //constructor: process options, 
    initialize: function(options) {
        this.setOptions(options);
        this.classOption1 = this.options.classOption1 * 10; //use option value to create a new value
    }
    
    //another method that does whatever I want
    myOtherCustomMethod: function() {
        
        //do something if the option is true...
        if(this.options.classOption2 == true) {
            
            //do something here because classOption2 is set to true
            this.classOption1 += 20;
        }
    }
    
});

Options are a simple but essential component to any MooTools Class!

Class Components: Implements

Implements is the Class property that allows you to add functionality from an existing MooTools class to a new class. Implementations can be used two ways. The first way is to use the Class "Implements" property directly within the class:

var MyClass = new Class({

    //implements
    Implements: [Options,Events],
    
    //constructor and more methods here...
    
});

Using the Implements property adds functionality from another class automatically with each instance of the new class. In the example above, functionality (class methods) from the Options and Events classes have been mixed into each instance of the new Class.

//the "Options" class...
var Options = new Class({
    setOptions: function(){
        var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
        if (!this.addEvent) return this;
        for (var option in options){
            if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
            this.addEvent(option, options[option]);
            delete options[option];
        }
        return this;
    }
});
    
//now "Implement" the options class...
var MyClass = new Class({

    //implements
    Implements: [Options,Events],
    
    //constructor and more methods here...
    
});

/*
    now MyClass has a "setOptions" method which will be provided to each class instance for use internally!
*/

//now "Implement" the options class...
var MyClass = new Class({

    //implements
    Implements: [Options,Events],
    
    //constructor
    initialize: function(options) {
        this.setOptions(options); //use setOptions which was provided by the Options implementation!
    }
});

The second method of implementing fresh functionality into a MooTools class is to use the baked-in "implements" Class method after a class has been created:

MyClass.implement({   
    //a new method available to 
    aNewMethod: function(arg1, arg2) {
        
        //"this" refers to the class
        //this method is available to all current and future instances
    }   
});

Each method works in the same fashion with the exception that the latter requires a separate statement which could be lost in translation when porting the class to a different site. Look to use the Implements property when creating the class as often as possible.

Back to the basic Implements usage, implementing the Options class provides you the ability to mix the default options with custom options passed in by the instance:

var MyClass = new Class({
    
    //implements
    Implements: [Options,Events],
    
    //constructor
    initialize: function(options) {
        this.setOptions(options); //use setOptions which was provided by the Options implementation!
    }
    
});

Events, a more advanced class, provides a unified method of providing callbacks for any "event" at any given time:

var MyClass = new Class({

    //implements
    Implements: [Options,Events],

    //constructor
    initialize: function(options) {
        this.setOptions(options); //use setOptions which was provided by the Options implementation!
    },
    
    //a custom method that does something and fires an "onCustomEvent" event
    myCustomMethod: function() {
        
        //do some processing and then...
        
        //...fire a custom event
        this.fireEvent('customEvent',[arg1,arg2]);
    }
});

As I said, events can be fired from anywhere within the class for any reason! You may broadcast events with as many arguments as you'd like.

Class Components: "initialize" (constructor)

The initialize method serves as the constructor for MooTools classes and runs immediately during instantiation. This method accepts any number of arguments provided when creating a class instance. The last argument should always be the class options (as they have already been set and the default options may match exactly what you would like) because all of the defaults could be perfect:

var MyClass = new Class({
    
    //options and Implements up here....
    
    //constructor
    initialize: function(arg1,arg2,options) {
        
        this.arg1 = arg1.replace('@',''); //make the argument available class-wide, remove '@' character if present
        this.arg2 = arg2; //make the argument available class-wide
        
        this.setOptions(options); //use setOptions which was provided by the Options implementation!
    },
    
    //more methods here...
    
});

The options should always be handled first, and since we used Implement to pull the Options class' methods, this.setOptions can be referenced to do just that. The initialize method is also the place to process options and set forth any "pre-processing" that should occur before the class is used. Pre-processing may include calling internal class methods or executing any special handling of class options or arguments. One example of frequently used pre-processing is wrapping a given option or argument in a document.id or $$ method to ensure the variable represents an element or element collection instead of a selector string:

var MyClass = new Class({
    
    //options and Implements up here....
    
    //constructor
    initialize: function(arg1,arg2,options) {

        this.arg1 = arg1; //make the argument available class-wide
        this.arg2 = $$(arg2); //wrap argument two with a $$ to make it an element collection

        this.setOptions(options); //use setOptions which was provided by the Options implementation!
    },

    //more methods here...

});

Regardless of what gets passed in, the object or string becomes what it should be!

Class Components: Methods

Believe it or not, the most basic and easiest part of creating a MooTools class is adding custom methods. Custom methods live within the main class object and provide key/value pairings much like the options object. Methods may be named in any manner (although camel-cased names are the JavaScript standard) and may accept any number of arguments. All class methods refer to the current instance as "this" so you may call other internal methods with this.methodName:

var MyClass = new Class({
    
    //Implements and initialize here...
    
    //a custom method that does anything you want
    myCustomMethod: function(arg) {
        
        //do some processing here
        
        //call another class method!
        this.myCustomMethod2(arg);
    },
    
    //another custom method
    myCustomMethod2: function(arg) {
        
        //do anything here too!
        
    }
});

Internal class binding will change the meaning of "this" as you would expect due to JavaScript object handling. This often occurs when adding an event listener to a given DOM node. MooTools includes a Function.prototype.bind method to ensure that the "this" keyword represents the class instance:

var MyClass = new Class({

    //Implements and initialize here...

    //a custom method that does anything you want
    myCustomMethod: function(arg) {
        
        //create a function where "this" is always the current class instance
        var myFn = function() {
            
            this.myCustomMethod2(arg);
            
        }.bind(this); //makes "this" always mean this class instance
        
    },

    //another custom method
    myCustomMethod2: function(arg) {

        //do anything here too!

    }
});

The other strategy for controlling what "this" represents is using a "self" variable which references the current class:

var MyClass = new Class({

    //Implements and initialize here...

    //a custom method that does anything you want
    myCustomMethod: function(arg) {
        
        //self is this
        var self = this;
        
        //create a function where "self" is always a "this" reference
        var myFn = function() {
            
            //call this class' myCustomMethod2, passing the one argument for myCustomMethod
            self.myCustomMethod2(arg);

        };

    },

    //another custom method
    myCustomMethod2: function(arg) {

        //do anything here too!

    }
});

Now the self variable can be used to reference the class throughout the entire method.

Extending MooTools Classes

One of the great advantages to using class-based frameworks like MooTools is that you can extend existing classes to avoid repeating code and keep the amount of code you do need for a specific class to a minimum. To create a new MooTools class while extending an existing class, all you need to do is add an Extends property to the overall Class object argument:

MyClass.MySubClass = new Class({

    //Extend "superclass"
    Extends: MyClass,
    
    //constructor, additional options, etc. below...
});

Extending an existing class in essence clones another class and uses it as a "starting point." Remember that since the original class is a dependency, it must be loaded before the new class. Additional options and arguments may also be provided to the new class:

MyClass.MySubClass = new Class({

    //Extend "superclass"
    Extends: MyClass,

    //additional options need only be declared; options from parent class may also be set
    options: {
        subclassOption1: 100,
        subclassOption2: false,
        subclassOption3: 'div',
        overriddenClassOption: 1
    }
    
    //constructor and custom methods here...
    
});

One very important practice to keep in mind while extending existing classes is that if you provide a method with the same name of a parent class, you will need to call the this.parent() method to run the parent class' method. It's also advisable to pass the method's arguments to that method when calling this.parent():

MyClass.MySubClass = new Class({

    //Extend "superclass"
    Extends: MyClass,

    //constructor and custom methods here...
    initialize: function(arg1,arg2,options) {
        this.parent(arg1,arg2,options); //runs parent class' initialize method
    }

});

You may run the parent class' method before you modify the arguments or after depending on the need to process arguments or results.

Extending classes is a complex process so carefully observe how the MooTools Request class becomes Request.JSON:

var Request = new Class({

    Implements: [Chain, Events, Options],

    options: {/*
        onRequest: function(){},
        onLoadstart: function(event, xhr){},
        onProgress: function(event, xhr){},
        onComplete: function(){},
        onCancel: function(){},
        onSuccess: function(responseText, responseXML){},
        onFailure: function(xhr){},
        onException: function(headerName, value){},
        onTimeout: function(){},
        user: '',
        password: '',*/
        url: '',
        data: '',
        headers: {
            'X-Requested-With': 'XMLHttpRequest',
            'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
        },
        async: true,
        format: false,
        method: 'post',
        link: 'ignore',
        isSuccess: null,
        emulation: true,
        urlEncoded: true,
        encoding: 'utf-8',
        evalScripts: false,
        evalResponse: false,
        timeout: 0,
        noCache: false
    },

    initialize: function(options){
        this.xhr = new Browser.Request();
        this.setOptions(options);
        this.headers = this.options.headers;
    },

    onStateChange: function(){
        var xhr = this.xhr;
        if (xhr.readyState != 4 || !this.running) return;
        this.running = false;
        this.status = 0;
        Function.attempt(function(){
            var status = xhr.status;
            this.status = (status == 1223) ? 204 : status;
        }.bind(this));
        xhr.onreadystatechange = function(){};
        clearTimeout(this.timer);

        this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
        if (this.options.isSuccess.call(this, this.status))
            this.success(this.response.text, this.response.xml);
        else
            this.failure();
    },

    isSuccess: function(){
        var status = this.status;
        return (status >= 200 && status < 300);
    },

    isRunning: function(){
        return !!this.running;
    },

    processScripts: function(text){
        if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
        return text.stripScripts(this.options.evalScripts);
    },

    success: function(text, xml){
        this.onSuccess(this.processScripts(text), xml);
    },

    onSuccess: function(){
        this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
    },

    failure: function(){
        this.onFailure();
    },

    onFailure: function(){
        this.fireEvent('complete').fireEvent('failure', this.xhr);
    },

    loadstart: function(event){
        this.fireEvent('loadstart', [event, this.xhr]);
    },

    progress: function(event){
        this.fireEvent('progress', [event, this.xhr]);
    },

    timeout: function(){
        this.fireEvent('timeout', this.xhr);
    },

    setHeader: function(name, value){
        this.headers[name] = value;
        return this;
    },

    getHeader: function(name){
        return Function.attempt(function(){
            return this.xhr.getResponseHeader(name);
        }.bind(this));
    },

    check: function(){
        if (!this.running) return true;
        switch (this.options.link){
            case 'cancel': this.cancel(); return true;
            case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
        }
        return false;
    },

    send: function(options){
        if (!this.check(options)) return this;

        this.options.isSuccess = this.options.isSuccess || this.isSuccess;
        this.running = true;

        var type = typeOf(options);
        if (type == 'string' || type == 'element') options = {data: options};

        var old = this.options;
        options = Object.append({data: old.data, url: old.url, method: old.method}, options);
        var data = options.data, url = String(options.url), method = options.method.toLowerCase();

        switch (typeOf(data)){
            case 'element': data = document.id(data).toQueryString(); break;
            case 'object': case 'hash': data = Object.toQueryString(data);
        }

        if (this.options.format){
            var format = 'format=' + this.options.format;
            data = (data) ? format + '&' + data : format;
        }

        if (this.options.emulation && !['get', 'post'].contains(method)){
            var _method = '_method=' + method;
            data = (data) ? _method + '&' + data : _method;
            method = 'post';
        }

        if (this.options.urlEncoded && ['post', 'put'].contains(method)){
            var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
            this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
        }

        if (!url) url = document.location.pathname;

        var trimPosition = url.lastIndexOf('/');
        if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);

        if (this.options.noCache)
            url += (url.contains('?') ? '&' : '?') + String.generateUID();

        if (data && method == 'get'){
            url += (url.contains('?') ? '&' : '?') + data;
            data = null;
        }

        var xhr = this.xhr;
        if (progressSupport){
            xhr.onloadstart = this.loadstart.bind(this);
            xhr.onprogress = this.progress.bind(this);
        }

        xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
        if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;

        xhr.onreadystatechange = this.onStateChange.bind(this);

        Object.each(this.headers, function(value, key){
            try {
                xhr.setRequestHeader(key, value);
            } catch (e){
                this.fireEvent('exception', [key, value]);
            }
        }, this);

        this.fireEvent('request');
        xhr.send(data);
        if (!this.options.async) this.onStateChange();
        if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
        return this;
    },

    cancel: function(){
        if (!this.running) return this;
        this.running = false;
        var xhr = this.xhr;
        xhr.abort();
        clearTimeout(this.timer);
        xhr.onreadystatechange = xhr.onprogress = xhr.onloadstart = function(){};
        this.xhr = new Browser.Request();
        this.fireEvent('cancel');
        return this;
    }

});

As described earlier, MooTools' Request class provides an abstraction for Ajax requests, much the way jQuery's $.ajax method does. All classes that extend this class get all of Request's methods, options, and functionality. Now let's create Request.JSON, which is a small departure from the Request class:

Request.JSON = new Class({

    Extends: Request,

    options: {
        secure: true
    },

    initialize: function(options){
        this.parent(options);
        Object.append(this.headers, {
            'Accept': 'application/json',
            'X-Request': 'JSON'
        });
    },

    success: function(text){
        var secure = this.options.secure;
        var json = this.response.json = Function.attempt(function(){
            return JSON.decode(text, secure);
        });

        if (json == null) this.onFailure();
        else this.onSuccess(json, text);
    }

});

Note how small the Request.JSON class is. Request.JSON's small codebase is due to the "Extends: Request" code; all of Requests's functionality was initially built into Request.JSON!

A Few Sample MooTools Classes

I've provided code samples along the way but it's extremely important that you see MooTools class samples in their entirety to get an idea of just how production-ready classes look. The first class I'll point out is my FontChecker class. FontChecker provides an almost foolproof method of checking if the user has a given font. The beauty of FontChecker is that it is a relatively simple class that's highly portable and compact because it's written in MooTools class format:

var FontChecker = new Class({
    /* implements */
    Implements: [Options],
    /* options */
    options: {
        fakeFont: '__RUBBUSH_FONT__',
        testString: 'abcdefghijklmnopqrstuvwxyz'
    },
    /* initialization */
    initialize: function(options) {
        //set options
        this.setOptions(options);
    },
    /* a method that does whatever you want */
    check: function(desiredFont) {
        /* create a hidden element */
        var element = new Element('span',{
            styles: {
                position: 'absolute',
                top: -10,
                right: -10,
                'font-family': this.options.fakeFont
            },
            html: this.options.testString
        }).inject(document.body);
        /* apply a fake font, get width */
        var width = element.getCoordinates().width;
        /* apply desired font */
        element.setStyle('font-family', desiredFont);
        var new_width = element.getCoordinates().width;
        /* take our temp element out of the DOM */
        element.dispose();
        /* compare widths to see check if font is available */
        return (width !== new_width);
    }
});

FontChecker implements the Options class, features a few options, and uses only one custom method to accomplish its task.

A more complex MooTools class is Dotter which features numerous to control the functionality of a given element's HTML:

var Dotter = new Class({

    /* implements */
    Implements: [Options,Events],

    /* options */
    options: {
        delay: 1000,
        dot: '.',
        message: 'Loading',
        numDots: 3,
        property: 'text',
        reset: false/*,
        onDot: $empty,
        onStart: $empty,
        onStop: $empty
        */
    },

    /* initialization */
    initialize: function(container,options) {
        /* set options */
        this.setOptions(options);
        this.container = document.id(container);
        this.dots = 0;
        this.running = false;
    },

    /* adds dot */
    dot: function() {
        if(this.running) {
            var text = this.container.get(this.options.property);
            this.dots++;
            this.container.set(this.options.property,(this.dots % this.options.numDots != 0 ? text : this.options.message) + '' + this.options.dot);
        }
        return this;
    },

    /* loads or resets the dotter */
    load: function() {
        this.loaded = true;
        this.dots = 0;
        this.dotter = function(){ this.dot(); this.fireEvent('dot'); }.bind(this);
        this.periodical = this.dotter.periodical(this.options.delay);
        this.container.set(this.options.property,this.options.message + '' + this.options.dot);
        return this;
    },

    /* start the dotter */
    start: function() {
        if(!this.loaded || this.options.reset) this.load();
        this.running = true;
        this.fireEvent('start');
        return this;
    },

    /* stop the dotter */
    stop: function() {
        this.running = this.loaded = false;
        $clear(this.periodical);
        this.fireEvent('stop');
        return this;
    }
});

Dotter accepts a "container" argument which represents the element to be controlled. Options are also accepted to modify default class settings.

Using MooTools Classes

Using a MooTools class is the most simple part of the class framework. Instantiating a class requires that you use the "new {class name}" statement:

var MyClassInstance = new MyClass(document.body,{
    classOption1: true,
    classOption2: false
});

An instance of MyClass is now stored in MyClassInstance. Arguments and options were passed to the constructor via the new MyClass declaration. A more detailed example of class usage could be seen using the MooTools Request class to make an AJAX request:

var request = new Request({
    url: 'get-users.php',
    method: 'post',
    data: {
        favoriteColor: 'blue',
        sex: 'male'
    },
    onRequest: function() {
        console.log('request sent...');
    },
    onFailure: function(response) {
        console.log('request failed...' + response);
    },
    onSuccess: function(response) {
        console.log('request successful...' + response);
    },
    onComplete: function(response) {
        console.log('request complete...' + response);
    }
}).send();

The small snippet above creates an AJAX request for "get-users.php" via POST transmission, sending important data with it. Event handlers (or callbacks) are added to log each step of the request.

There are no hard and fast rules for how you should name your class instances but a naming convention which using the class name as a prefix is great habit:

//for FontChecker
var fontChecker = new FontChecker();
var hasArial = fontChecker.check('Arial');

//for Request
var getContentRequest = new Request({
    url: 'somefile.php',
    onSuccess: function(response) {
        document.id('myDiv').set('html',response);
    }
})

Class Scope

MooTools classes are traditionally created in the global namespace as there are obvious advantages to being able to create an instance of a class from anywhere within the page. You can, however, create limited-scope by using a simple closure to encapsulate the class:

(function() {
    
    //class limited in scope
    var MyClass = new Class({
        
        //class properties in here
        
    });
    
    //use the class!
    var MyClassInstance = new MyClass({ /* some options */ });
    
})();

//MyClass is undefined out of the closure above.
var MyClassInstance = new MyClass({ /* options */ }); //undefined! error!

You can also store your classes in a scoped object to cut down on the number of variables in use within a given scope:

//creating my own "namespace"
DWClasses = {};

//create classes onto "namespace"
DWClasses.MyClass = new Class({
    //class properties here
});

//use it!
var MyClassInstance = new DWClasses.MyClass(/* options */);

The scope of your classes can be as large or small as you'd like! What's important is that you find an organizational structure that works best for your web application.

MooTools FTW!

The MooTools JavaScript framework has layers upon layers of great code but the class system is its most practical, logical, and useful. MooTools' solid inheritance system works to eliminate repeated code and increase efficiency while keeping your web application maintainable and compact. Give MooTools a try &mdash you'll be surprised just how easy and enjoyable it will make your front-end development!

 

About the Author

David Walsh is a MooTools Core Developer and all around JavaScript fanboy.  His expertise is in JavaScript (MooTools, Dojo, jQuery), CSS, and PHP.  David blogs about front-end web topics and evangelizes MooTools at his blog, which you may find at https://davidwalsh.name.  Webmasters need not apply.

David works for SitePen, the prestigious JavaScript development shop.  He spends his days knee-deep in Dojo, Dijit, and other JavaScript APIs, creating usable and flexible web applications.  Flanked by open source pioneers, David learns an immense amount about JavaScript and front-end technologies every day.

When his text editor is closed, David enjoys playing soccer, watching Arsenal run rampant on the English Premier League, and spending time with his beautiful wife.  David is often mistaken for Kid Rock and Kurt Cobain, neither of which is considered a compliment.  David lives in Madison, WI.

MooTools FTW..

Find David on: